Email OTP
Email OTP (One-Time Password) provides passwordless authentication using 6-digit numeric codes. Better for mobile where clicking links is less convenient.
How It Works
Section titled “How It Works”-
Request an OTP
Via the built-in endpoint:
POST /auth/otp Content-Type: application/json {"email": "user@example.com"}POST /auth/otp Content-Type: application/json {"email": "user@example.com"}Always returns 200 regardless of whether the email exists (prevents enumeration).
Or programmatically:
code = await auth.create_email_otp(email) # Returns 6-digit string, or None if user not foundcode = await auth.create_email_otp(email) # Returns 6-digit string, or None if user not found -
Deliver the code
Use the
email_otp_requestedevent hook:@auth.on("email_otp_requested") async def send_otp(event): await send_email( to=event.email, body=f"Your code: {event.code}", )@auth.on("email_otp_requested") async def send_otp(event): await send_email( to=event.email, body=f"Your code: {event.code}", ) -
Verify and login
Via the built-in endpoint:
POST /auth/otp/verify Content-Type: application/json {"email": "user@example.com", "code": "847291"}POST /auth/otp/verify Content-Type: application/json {"email": "user@example.com", "code": "847291"}Returns an
AuthResponsewith tokens and user data. Sets cookies automatically if cookie mode is enabled.Or programmatically:
result = await auth.verify_email_otp(email, code) # Returns AuthResponse with tokens and userresult = await auth.verify_email_otp(email, code) # Returns AuthResponse with tokens and user
Auto-Signup
Section titled “Auto-Signup”By default, OTP only works for existing users. Set allow_passwordless_signup=True to auto-create accounts:
auth = AuthFort(
database_url="...",
allow_passwordless_signup=True,
) auth = AuthFort(
database_url="...",
allow_passwordless_signup=True,
) Email Verification
Section titled “Email Verification”OTP login automatically sets email_verified=True — no separate verification step needed.
Security
Section titled “Security”| Property | Detail |
|---|---|
| Code format | 6-digit numeric (1,000,000 combinations) |
| Code lifetime | Single-use, expires after email_otp_ttl (default: 5 minutes) |
| Cross-user protection | The email in the verify request must match the user who requested the OTP |
| Ban enforcement | Banned users cannot use OTP |
Events
Section titled “Events”Emits email_otp_requested (includes code for delivery), email_otp_login, and optionally user_created (if auto-signup creates a new account).
See Events & Hooks for all events and their payloads.
Client SDK
Section titled “Client SDK”await auth.requestOTP('user@example.com');
// User enters the 6-digit code
const user = await auth.verifyOTP('user@example.com', '847291'); await auth.requestOTP('user@example.com');
// User enters the 6-digit code
const user = await auth.verifyOTP('user@example.com', '847291');