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.
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
| Code | Status | Meaning |
|---|---|---|
MISSING_EMAIL | 400 | No email in body |
MISSING_CODE | 400 | No code in body (verify only) |
RATE_LIMITED | 429 | Cooldown on send, or too many bad verifies |
INVALID_CODE | 401 | Wrong code, expired, or already used |
EMAIL_SEND_FAILED | 500 | Provider rejected the send |
Testing
In dev mode, skip the email entirely:When to choose magic codes vs alternatives
| Magic codes | Password | OAuth |
|---|---|---|
| ✅ Zero memory load on user | ❌ Users forget passwords | ✅ Familiar to users |
| ✅ Email is verified by construction | ❌ Email verification is a separate step | ✅ No credentials your service stores |
| ✅ No password reset flow needed | ❌ Need reset flow | ✅ Provider handles 2FA |
| ❌ Email deliverability matters | ✅ Works without email | ❌ Requires app registration with provider |
| ❌ Slower than typing a password | ✅ Fast for repeat users | ✅ One click after first use |