Two-Factor Authentication (2FA)
Two-factor authentication adds a second verification step to user login, protecting accounts even if passwords are compromised. Auth Block supports two channels:
| Channel | How It Works | Best For |
|---|---|---|
| Email OTP | 6-digit code sent to user's email | Zero-friction setup, no app required |
| Authenticator App (TOTP) | 6-digit code from an authenticator app | Stronger security, works offline |
MFA is opt-in per user. Users who don't enable it continue logging in with just their password. No existing flows break.
Setting Up 2FA
Option A: Email 2FA
Email 2FA sends a 6-digit code to the user's registered email address during login. No app installation required.
To enable:
- Navigate to your account security settings
- Select Email as your 2FA method
- A verification code is sent to your email
- Enter the code to confirm setup
- Save your 10 backup codes somewhere safe
Option B: Authenticator App (TOTP)
TOTP 2FA uses a time-based one-time password generated by an authenticator app on your phone.
Supported apps:
- Google Authenticator (iOS/Android)
- Authy (iOS/Android/Desktop)
- 1Password
- Bitwarden
- Microsoft Authenticator
To enable:
- Navigate to your account security settings
- Select Authenticator App as your 2FA method
- Scan the QR code with your authenticator app
- Can't scan? Use Manual entry — copy the secret key and add it to your app manually
- Enter the 6-digit code displayed in your app to verify
- Save your 10 backup codes somewhere safe
Backup Codes
When you enable 2FA, you receive 10 one-time backup codes. Each code can only be used once.
Store these securely — they are your recovery method if you lose access to your email or phone.
- Print them and keep in a safe place
- Save them in a password manager
- Do not store them on the same device as your authenticator app
Disabling 2FA
To disable 2FA, go to your security settings and confirm with your password. This removes the second factor requirement from your account.
Logging In with 2FA
With Email OTP
- Enter your email and password as usual
- A 6-digit code is sent to your email
- Enter the code within 10 minutes
- You're logged in
With Authenticator App
- Enter your email and password as usual
- Open your authenticator app
- Enter the current 6-digit code (codes refresh every 30 seconds)
- You're logged in
Using a Backup Code
If you've lost access to your email or phone:
- Enter your email and password as usual
- When prompted for a 2FA code, enter one of your backup codes instead
- The backup code is consumed (can't be reused)
- You're logged in — consider setting up a new 2FA method
Developer Guide: Integrating MFA
API Endpoints
All MFA endpoints are under /users/:unique_id/mfa/:
| Endpoint | Method | Description |
|---|---|---|
/mfa/setup | POST | Initialize MFA setup |
/mfa/enable | POST | Activate MFA after verification |
/mfa/disable | POST | Deactivate MFA (requires password) |
/mfa/verify | POST | Validate a code or backup code |
/mfa/status | GET | Check current MFA state |
Setup MFA
TOTP (Authenticator App)
curl -X POST https://auth.api.us.23blocks.com/users/usr_abc123/mfa/setup \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{ "channel": "totp" }'
Response:
{
"data": {
"id": "mfa_setup_123",
"type": "mfa_setup",
"attributes": {
"channel": "totp",
"secret": "JBSWY3DPEHPK3PXP",
"qr_code_uri": "otpauth://totp/YourApp:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=YourApp",
"backup_codes": [
"12345678", "23456789", "34567890", "45678901", "56789012",
"67890123", "78901234", "89012345", "90123456", "01234567"
]
}
}
}
Rendering the QR code: Use the qr_code_uri (an otpauth:// URI) to generate a QR code image on your frontend. Libraries like qrcode.js or react-qr-code can render it directly.
Manual entry fallback: Display the secret value for users who can't scan the QR code. They enter it manually in their authenticator app.
Email OTP
curl -X POST https://auth.api.us.23blocks.com/users/usr_abc123/mfa/setup \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{ "channel": "email" }'
A verification code is sent to the user's email. The response includes backup codes.
Enable MFA
After the user verifies their setup code:
For TOTP:
curl -X POST https://auth.api.us.23blocks.com/users/usr_abc123/mfa/enable \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{ "totp_code": "123456" }'
For Email:
curl -X POST https://auth.api.us.23blocks.com/users/usr_abc123/mfa/enable \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{ "channel": "email" }'
Disable MFA
Requires the user's password for security:
curl -X POST https://auth.api.us.23blocks.com/users/usr_abc123/mfa/disable \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{ "password": "UserPassword123" }'
Verify a Code
Validate a TOTP code, email OTP, or backup code:
curl -X POST https://auth.api.us.23blocks.com/users/usr_abc123/mfa/verify \
-H "Authorization: Bearer your-jwt-token" \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{ "code": "123456" }'
For backup codes, send the backup code as the code value. It will be consumed on successful verification.
Check MFA Status
curl -X GET https://auth.api.us.23blocks.com/users/usr_abc123/mfa/status \
-H "Authorization: Bearer your-jwt-token" \
-H "X-API-Key: your-api-key"
Response:
{
"data": {
"id": "usr_abc123",
"type": "mfa_status",
"attributes": {
"mfa_enabled": true,
"mfa_channel": "totp",
"backup_codes_remaining": 9
}
}
}
Handling MFA in Login Flow
When a user with MFA enabled signs in, the response includes mfa_required:
Step 1: Normal sign-in attempt
curl -X POST https://auth.api.us.23blocks.com/auth/sign_in \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"email": "user@example.com",
"password": "SecurePassword123"
}'
Response when MFA is required:
{
"data": {
"id": "usr_abc123",
"type": "user",
"attributes": {
"unique_id": "usr_abc123",
"mfa_required": true,
"mfa_channel": "totp"
}
}
}
Step 2: Submit MFA code
curl -X POST https://auth.api.us.23blocks.com/auth/sign_in \
-H "Content-Type: application/json" \
-H "X-API-Key: your-api-key" \
-d '{
"email": "user@example.com",
"password": "SecurePassword123",
"mfa_code": "123456"
}'
This returns the full user object with JWT on success.
Same flow applies to passwordless verify (POST /auth/passwordless/verify) — if the user has MFA enabled, they must provide the MFA code alongside the OTP.
User Serializer Fields
The user object now includes MFA fields:
| Field | Type | Description |
|---|---|---|
mfa_enabled | boolean | Whether MFA is active |
mfa_channel | string | null | "email", "totp", or null if not enabled |
UX Best Practices
Backup code recovery:
- Show backup codes on a dedicated screen after setup
- Allow the user to copy or download them
- Remind users who haven't saved codes
- Display remaining backup code count in security settings
QR code rendering:
- Use the
qr_code_urifrom the setup response — it's a standardotpauth://URI - Always show the manual
secretas a fallback below the QR code - Label the entry clearly so users can identify it in their authenticator app
Channel selection:
- Present Email as the simpler option (no app required)
- Present TOTP as the stronger option (works offline, not vulnerable to email compromise)
- Let users switch channels by disabling and re-enabling MFA
Tenant Admin Guide
MFA Adoption
MFA is opt-in per user. There is no tenant-wide enforcement setting at this time. Administrators can check MFA adoption across their user base by querying user records for the mfa_enabled field.
Security Recommendations
| User Role | Recommendation |
|---|---|
| Admin / Owner | Strongly encourage TOTP (authenticator app) |
| Regular users | Encourage Email OTP as a low-friction starting point |
| API-only accounts | MFA not applicable — use service tokens instead |
| High-security roles | Require TOTP and verify backup codes are saved |
Monitoring
- Track
mfa_enabledandmfa_channelfields across your user base - Monitor backup code usage — high usage may indicate users losing access to their primary 2FA method
- Audit MFA setup/disable events for suspicious patterns