How it works
User row with that email and stamps emailVerified — typing the code proves control of the address.
Send a code
PYLON_DEV_MODE=true) the response also includes dev_code so you can sign in without configuring an email provider:
Verify a code
token and pass it as Authorization: Bearer pylon_a1b2c3... on subsequent requests.
From the SDKs
Built-in security
- Constant-time code comparison — no timing leak.
- 5-attempt cap per code — burned after 5 wrong tries; even a correct subsequent attempt returns
RATE_LIMITED. - 10-minute expiry — codes are short-lived.
- 60-second send cooldown per email — clients can’t flood a user with codes. Returns
429 RATE_LIMITEDwithretry_after_secs. - Single-use — verifying a code consumes it.
- CSPRNG-generated — codes are uniform random in
0..1_000_000.
Configuring email delivery
Magic codes need an email provider configured, otherwise they only work in dev mode. Pylon supports:Settings → Email for production use to keep deliverability high.
If you set PYLON_EMAIL_PROVIDER=webhook, also set PYLON_EMAIL_ENDPOINT to your custom URL — Pylon POSTs { to, from, subject, body } to it.
To give auth email its own key and from-address — separate from your app’s ctx.email — set the PYLON_AUTH_EMAIL_* family (_PROVIDER, _API_KEY, _FROM, _ENDPOINT); it overrides PYLON_EMAIL_* for auth flows only. See Auth → Configuration.
See Stack0, Resend, SendGrid for transactional sending services.
Customizing the email
The default subject is “Your sign-in code” and the body is plain text:magic/send server-side and ships your own templated email instead. The plugin system also supports replacing the email transport — see Plugins → Integrations.
Error responses
Testing
In dev mode, skip the email entirely:When to choose magic codes vs alternatives
Most apps should ship magic codes first, then add OAuth for one-click sign-in once they have users. Password is the third option, useful when email isn’t an option (e.g. shared device with no email access).