MFA Endpoints
API reference for all multi-factor authentication endpoints. These endpoints handle MFA verification during sign-in, TOTP and SMS enrollment, backup code generation, and MFA status checks.
All endpoints require Content-Type: application/json. Endpoints marked with Bearer JWT require a valid JWT in the Authorization header. See the MFA guide for flow diagrams and integration patterns.
Verify MFA
Complete MFA verification during sign-in. Exchanges a challenge token and MFA code for a JWT and refresh token.
Request body
- Name
challenge- Type
- string
- Description
The challenge token returned by primary authentication when MFA is required.
- Name
code- Type
- string
- Description
The MFA code. A 6-digit TOTP code, 6-digit SMS code, or an 8-character backup code.
- Name
method- Type
- string
- Description
The MFA method to verify against. One of:
totp,sms, orbackup_codes.
Response 200
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "rt_a1b2c3d4e5f6...",
"user": {
"id": "user_abc123",
"email": "jane@example.com",
"name": "Jane Doe",
"email_verified": true
}
}
- Name
token- Type
- string
- Description
A short-lived JWT (5-minute expiry).
- Name
refresh_token- Type
- string
- Description
A long-lived refresh token for session management. See Session Management.
- Name
user- Type
- object
- Description
The authenticated user object.
Error responses
| Status | Error |
|---|---|
400 | Missing or invalid fields |
401 | Invalid challenge, expired challenge, or wrong code |
404 | MFA method not enrolled for user |
415 | Invalid Content-Type |
429 | Rate limited |
Rate limits
- 5 attempts per 15 minutes per IP address
Challenge tokens expire after 5 minutes. If the challenge expires, the user must start primary authentication again. Failed verification attempts do not consume the challenge — the same challenge can be retried until the rate limit or expiry is reached.
Example request
curl -X POST https://auth.example.com/api/proxy/mfa/verify \
-H "Content-Type: application/json" \
-d '{
"challenge": "ch_a1b2c3d4e5f6...",
"code": "123456",
"method": "totp"
}'
Example response
{
"token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "rt_a1b2c3d4e5f6...",
"user": {
"id": "user_abc123",
"email": "jane@example.com",
"name": "Jane Doe",
"email_verified": true
}
}
TOTP setup
Generate a TOTP secret and QR code for the user to scan with their authenticator app. Requires a valid JWT.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Response 200
{
"secret": "JBSWY3DPEHPK3PXP",
"qr_code": "data:image/png;base64,iVBORw0KGgo...",
"uri": "otpauth://totp/AuthGate:jane@example.com?secret=JBSWY3DPEHPK3PXP&issuer=AuthGate"
}
- Name
secret- Type
- string
- Description
The TOTP secret in Base32 encoding. Display this for manual entry if the user cannot scan the QR code.
- Name
qr_code- Type
- string
- Description
A data URI containing a PNG image of the QR code. Display this as an
<img>element.
- Name
uri- Type
- string
- Description
The
otpauth://URI encoded in the QR code. Can be used to generate a custom QR code.
Error responses
| Status | Error |
|---|---|
401 | Missing or invalid JWT |
409 | TOTP is already set up for this user |
429 | Rate limited |
The TOTP secret is not activated until it is verified with the verify-setup endpoint. If the user abandons setup, the pending secret is discarded.
Verify TOTP setup
Confirm TOTP setup by verifying a code from the user's authenticator app. This activates TOTP MFA for the user. Requires a valid JWT.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Request body
- Name
code- Type
- string
- Description
A 6-digit TOTP code from the user's authenticator app.
Response 200
{
"success": true
}
Error responses
| Status | Error |
|---|---|
400 | Missing or invalid code format |
401 | Missing or invalid JWT, or incorrect TOTP code |
404 | No pending TOTP setup found (call setup first) |
415 | Invalid Content-Type |
429 | Rate limited |
Example request
curl -X POST https://auth.example.com/api/proxy/mfa/totp/verify-setup \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Example response
{
"success": true
}
Remove TOTP
Remove TOTP MFA from the user's account. Requires a valid JWT and a current TOTP code for confirmation.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Request body
- Name
code- Type
- string
- Description
A current 6-digit TOTP code to confirm the removal.
Response 200
{
"success": true
}
Error responses
| Status | Error |
|---|---|
400 | Missing or invalid code format |
401 | Missing or invalid JWT, or incorrect TOTP code |
403 | Cannot remove TOTP when MFA policy is "required" and no other method is enrolled |
404 | TOTP is not set up for this user |
415 | Invalid Content-Type |
429 | Rate limited |
Enable SMS MFA
Enable SMS as an MFA method for the user. The user must have a verified phone number on their account. Requires a valid JWT.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Response 200
{
"success": true
}
Error responses
| Status | Error |
|---|---|
400 | User has no verified phone number |
401 | Missing or invalid JWT |
409 | SMS MFA is already enabled for this user |
429 | Rate limited |
Remove SMS MFA
Remove SMS as an MFA method from the user's account. Requires a valid JWT.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Response 200
{
"success": true
}
Error responses
| Status | Error |
|---|---|
401 | Missing or invalid JWT |
403 | Cannot remove SMS when MFA policy is "required" and no other method is enrolled |
404 | SMS MFA is not enabled for this user |
429 | Rate limited |
Send SMS code
Send an MFA verification code via SMS during the challenge flow. This endpoint does not require a JWT — it uses the challenge token to identify the user.
Request body
- Name
challenge- Type
- string
- Description
The challenge token returned by primary authentication.
Response 200
{
"success": true
}
Error responses
| Status | Error |
|---|---|
400 | Missing challenge in request body |
401 | Invalid or expired challenge token |
404 | SMS MFA is not enabled for this user |
415 | Invalid Content-Type |
429 | Rate limited |
500 | SMS delivery failed |
This endpoint is rate-limited independently from the MFA verify endpoint. If SMS delivery fails, the user can retry or switch to another MFA method (TOTP or backup codes).
Generate backup codes
Generate a new set of 10 backup codes. Any existing backup codes are invalidated. Requires a valid JWT.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Response 200
{
"codes": [
"a1b2c3d4",
"e5f6g7h8",
"i9j0k1l2",
"m3n4o5p6",
"q7r8s9t0",
"u1v2w3x4",
"y5z6a7b8",
"c9d0e1f2",
"g3h4i5j6",
"k7l8m9n0"
]
}
- Name
codes- Type
- string[]
- Description
An array of 10 single-use backup codes. Each code is 8 alphanumeric characters.
Error responses
| Status | Error |
|---|---|
401 | Missing or invalid JWT |
403 | User must have at least one other MFA method enrolled before generating backup codes |
429 | Rate limited |
This is the only time the backup codes are returned in plaintext. AuthGate stores only hashed versions. If the user loses their codes, they must generate a new set.
Example request
curl -X POST https://auth.example.com/api/proxy/mfa/backup-codes/generate \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Example response
{
"codes": [
"a1b2c3d4",
"e5f6g7h8",
"i9j0k1l2",
"m3n4o5p6",
"q7r8s9t0",
"u1v2w3x4",
"y5z6a7b8",
"c9d0e1f2",
"g3h4i5j6",
"k7l8m9n0"
]
}
MFA status
Check the current MFA enrollment status for the authenticated user. Requires a valid JWT.
Authentication
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Response 200
{
"enrolled": true,
"methods": ["totp", "sms", "backup_codes"],
"required": true
}
- Name
enrolled- Type
- boolean
- Description
Whether the user has any MFA method enrolled.
- Name
methods- Type
- string[]
- Description
The MFA methods currently enrolled. Possible values:
totp,sms,backup_codes.
- Name
required- Type
- boolean
- Description
Whether the project's MFA policy requires MFA for all users.
Error responses
| Status | Error |
|---|---|
401 | Missing or invalid JWT |
429 | Rate limited |
Example request
curl https://auth.example.com/api/proxy/mfa/status \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Example response
{
"enrolled": true,
"methods": ["totp", "backup_codes"],
"required": false
}