Multi-Factor Authentication (MFA)
MFA enrollment and verification are integrated into the login flow.
MFA Flow
Initial Login (MFA Not Enrolled)
When logging in for the first time or when MFA is not yet configured:
Request:
POST /api/login/local
{
"username": "admin",
"password": "password123"
}
Response (MFA Setup Required):
{
"mfaConfigs": [
{
"id": "totp",
"name": "Authenticator App",
"setupComponent": "totp-setup",
"qrCode": "data:image/png;base64,iVBORw0KGgo...",
"secret": "BASE32ENCODEDSECRET"
}
],
"loginTicket": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
The client should:
- Display the QR code for the user to scan
- Prompt user to enter verification code from authenticator app
- Submit code to complete setup
Complete MFA Setup
Request:
POST /api/login/local
{
"username": "admin",
"mfaConfig": {
"loginTicket": "jwt-from-previous-response",
"code": "123456"
}
}
Response (Setup Success):
{
"user": { ... },
"sid": "session-id",
"jwt": "jwt-token",
"wsToken": "ws-token",
"locale": "en-US",
"lang": "en"
}
Error Response:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Invalid authenticator code"
}
Login with MFA Enabled
When MFA is already enrolled:
Step 1: Initial Login
POST /api/login/local
{
"username": "admin",
"password": "password123"
}
Response:
{
"loginTicket": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"verifyConfig": {
"component": "totp-verify"
}
}
Step 2: Verify MFA Code
POST /api/login/local
{
"username": "admin",
"mfaConfig": {
"loginTicket": "jwt-from-step-1",
"code": "654321"
}
}
Response (Success):
{
"user": { ... },
"sid": "session-id",
"jwt": "jwt-token",
"wsToken": "ws-token"
}
MFA Configuration
Tenant-Level Enablement
MFA must be enabled at the tenant level before users can enroll.
Check Available Authenticators:
Available authenticators are determined by:
- Tenant configuration
- Domain eligibility
- Driver implementation
Supported Authenticator Types
| Type | Description | Setup Component |
|---|---|---|
totp | Time-based One-Time Password (Google Authenticator, Authy, etc.) | totp-setup |
Login Ticket
The login ticket is a JWT token that maintains state between login steps:
Contains:
username- User attempting to log intenant- Tenant IDdomain- Authentication domain
Purpose:
- Prove successful password authentication
- Prevent replay attacks
- Maintain security during MFA flow
Expiration:
- Short-lived (typically 5-10 minutes)
- Single-use
Pre-blocks in Login Flow
The login route includes these MFA-related pre-blocks:
- loginTicket - Verify login ticket if provided
- enabledAuthenticators - Check which MFA methods are enabled
- mfaEnabled - Determine if MFA is required
- activeAuthenticator - Check if user has enrolled MFA
- maybeCreateLoginTicket - Create login ticket after password auth
- maybeSetupAuthenticator - Provide setup instructions if not enrolled
- mfaValidate - Verify MFA code
MFA Management
Enrollment
Users enroll in MFA during the login process when:
- MFA is enabled for the tenant
- User has successfully authenticated with password
- User has not yet enrolled
Unenrollment
MFA unenrollment is typically done through:
- User settings endpoints (see User API documentation)
- Admin override (for account recovery)
Recovery
If a user loses access to their MFA device:
- Admin can disable MFA for the user
- User must re-enroll on next login
Domain Eligibility
Not all authentication domains support MFA:
- Local Domain: MFA supported
- SSO/SAML: MFA handled by IdP
- LDAP: May support MFA depending on configuration
The isDomainEligible() driver method determines if MFA can be used for a specific domain.
Security Considerations
Backup Codes
Consider implementing backup codes for account recovery:
- Generate one-time use codes during enrollment
- Store securely (hashed)
- Allow use when primary MFA method unavailable
Rate Limiting
MFA verification should be rate-limited:
- Prevent brute force attacks
- Lock account after N failed attempts
Time Skew
TOTP codes have a time window:
- Typically 30-second intervals
- Allow 1-2 time steps of skew for clock differences
Always use HTTPS for MFA flows to prevent token interception. Login tickets and MFA codes should never be transmitted over unencrypted connections.
The two-step MFA flow (password → code) provides better security than embedding the code in the initial login request, as it proves both factors separately.