Verify MFA (Login)
Completes the login process for users with MFA enabled. When POST /auth/login returns mfaRequired: true, this endpoint must be called with the MFA challenge token and a verification code (either a 6-digit TOTP code from the authenticator app or an 8-character recovery code).
Request
POST /auth/verify-mfa
Authentication
This is a public endpoint. No authentication header is required, but you must provide the mfaChallengeToken received from the login response.
Request Body
{
"mfaChallengeToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"code": "123456"
}
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
mfaChallengeToken | string | Yes | Temporary token returned in the login response when mfaRequired: true. Valid for a short time window (typically 5 minutes). |
code | string | Yes | Either a 6-digit TOTP code from the authenticator app OR an 8-character recovery code. Must be 6-12 characters. |
Response
Returns an AuthResponse object with access and refresh tokens.
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600
}
Response Fields
| Field | Type | Description |
|---|---|---|
accessToken | string | JWT access token for API authentication. Include in Authorization: Bearer <token> header. |
refreshToken | string | JWT refresh token for obtaining new access tokens when they expire. |
tokenType | string | Always "Bearer" for JWT tokens. |
expiresIn | integer | Access token lifetime in seconds (typically 3600 = 1 hour). |
Error Responses
| Status Code | Error | Description |
|---|---|---|
| 400 | Bad Request | Invalid or missing code, or invalid challenge token format |
| 401 | Unauthorized | Incorrect TOTP code, expired/invalid challenge token, or recovery code already used |
| 429 | Too Many Requests | Rate limit exceeded for MFA verification attempts |
Example
Request with TOTP Code
curl -X POST https://api.entryguard.io/api/v1/auth/verify-mfa \
-H "Content-Type: application/json" \
-d '{
"mfaChallengeToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"code": "123456"
}'
Request with Recovery Code
curl -X POST https://api.entryguard.io/api/v1/auth/verify-mfa \
-H "Content-Type: application/json" \
-d '{
"mfaChallengeToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c",
"code": "a1b2c3d4"
}'
Response
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzZmE4NWY2NC01NzE3LTQzNjItYjk4Zi05ZGRkMzZlNGIwMTAiLCJvcmdJZCI6IjdlNDJhOGYzLWM5MTItNGFjZi04NzZkLWIzZDc4ZmE2YWIyMSIsInJvbGVzIjpbIlVTRVIiXSwiaWF0IjoxNjQwOTk1MjAwLCJleHAiOjE2NDA5OTg4MDB9.K7Zz8yXqY5sC3vF9wA2hN8jR4tQ6pL1mE0nO7bG5iD8",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIzZmE4NWY2NC01NzE3LTQzNjItYjk4Zi05ZGRkMzZlNGIwMTAiLCJ0eXBlIjoicmVmcmVzaCIsImlhdCI6MTY0MDk5NTIwMCwiZXhwIjoxNjQzNTg3MjAwfQ.M5nP8qR2vX9wB3tL6sD4eA1jC7bF9kO0mH3yG8nI5rE",
"tokenType": "Bearer",
"expiresIn": 3600
}
Login Flow with MFA
- User submits email/password to
POST /auth/login - Server returns
{ "mfaRequired": true, "mfaChallengeToken": "..." } - Client prompts user for MFA code
- User enters 6-digit TOTP code (or recovery code)
- Client calls
POST /auth/verify-mfawith challenge token and code - Server validates code and returns access + refresh tokens
- Client stores tokens and proceeds with authenticated session