Overview
Passwordless authentication allows users to sign in without a traditional password. Instead, users receive one-time codes (OTP) via email or SMS. SuperTokens Core implements a secure device-based flow with support for both link codes and user input codes.Core Concepts
Devices
A device represents an authentication attempt. Each device:- Is associated with an email or phone number
- Can have multiple codes (for retry scenarios)
- Tracks failed authentication attempts
- Has a unique device ID and device ID hash
Codes
Two types of codes are supported:- User Input Code: 6-digit numeric code (e.g., “123456”)
- Link Code: Long alphanumeric code embedded in magic links
Create Code
Generate a one-time code for authentication.Implementation
Implementation:io.supertokens.passwordless.Passwordless.createCode() - View source
Process:
- Generate or use existing device ID
- Generate 6-digit user input code (if not provided)
- Generate link code using HMAC-SHA256
- Create device (if new) or add code to existing device
- Return all code information
API Endpoint
POST/recipe/signinup/code
Request Body (New Device):
Code Generation Details
User Input Code:- 6 random digits (0-9)
- Generated using
SecureRandom - Easy for users to type
Consume Code
Verify and consume a one-time code to authenticate.Implementation
Implementation:io.supertokens.passwordless.Passwordless.consumeCode() - View source
Verification Process:
- Look up code by link code hash or user input code
- Verify code hasn’t expired
- Check failed attempt limits
- Verify device ID hash matches
- Create or retrieve user
- Delete all codes for the email/phone
- Return user information
API Endpoint
POST/recipe/signinup/code/consume
Request Body (Using Link Code):
Device Management
Get Device Codes
Retrieve all active codes for a device. Implementation:io.supertokens.passwordless.Passwordless.getDeviceWithCodesById() - View source
API Endpoint:
GET /recipe/signinup/codes?deviceId={deviceId}
Response:
Delete Codes
Remove codes by email, phone number, or individual code ID. By Email: POST/recipe/signinup/codes/remove
User Operations
Update User
Update user’s email or phone number. Implementation:io.supertokens.passwordless.Passwordless.updateUser() - View source
Process:
- Validate at least one contact method remains
- Check for duplicate email/phone
- Update user record
- Clean up old devices
/recipe/user
Request Body:
Get User
Retrieve user by ID, email, or phone number. By Email: GET/recipe/user?email={email}
By Phone:
GET /recipe/user?phoneNumber={phoneNumber}
By ID:
GET /recipe/user?userId={userId}
Security Features
Code Expiration
Codes automatically expire after a configurable lifetime (default: 15 minutes). Configuration:Rate Limiting
Failed attempts are tracked per device:- Maximum attempts: Configurable (default: 5)
- After max attempts: Device is deleted
- Cooldown period: N/A (device deletion enforces rate limit)
Device ID Hashing
Device IDs are hashed before storage:- Device ID enumeration
- Timing attacks
- Direct device access without knowing the full device ID
Link Code Security
- HMAC-SHA256: Link codes use cryptographic hashing
- Unique salt per device: Each device has a unique salt
- Hash storage: Only link code hashes are stored
- One-time use: Codes are deleted after consumption
Code Lifecycle
Configuration
Core Settings
Email/SMS Integration
SuperTokens Core does NOT send emails or SMS directly. You must:- Implement email/SMS sending in your application
- Call the create code API
- Send the code to the user via your preferred service
- User submits code back to consume code API
Error Handling
Common Exceptions
RestartFlowException: Device/code not found, user must start overExpiredUserInputCodeException: Code has expiredIncorrectUserInputCodeException: Invalid code enteredDeviceIdHashMismatchException: Device ID doesn’t matchDuplicateEmailException: Email already in useDuplicatePhoneNumberException: Phone number already in useUserWithoutContactInfoException: Update would remove all contact methods
Best Practices
- Short expiry times: Keep code lifetime under 15 minutes
- Limit retries: Set reasonable max attempt limits (5-10)
- Secure delivery: Use reputable email/SMS providers
- Rate limiting: Implement rate limiting on code creation
- User feedback: Show remaining attempts on failed codes
- Cleanup: Old codes are automatically cleaned by cron jobs
- Phone validation: Validate phone numbers in E.164 format
- Email verification: Email is auto-verified on successful code consumption
Advanced Features
Bulk Import
Import passwordless users in bulk: Implementation:io.supertokens.passwordless.Passwordless.createPasswordlessUsers() - View source
Multi-Tenancy
- Users are isolated per tenant
- Each tenant has independent code expiry settings
- Email/phone uniqueness enforced per tenant
Account Linking
Passwordless accounts can be linked with:- Email/password accounts
- Social login accounts
- WebAuthn accounts