Verify 2FA
Verify 2FA code and complete authentication. This is the only point where MFA-enabled logins receive authenticated session artifacts. When auth.2fa_challenge=true, send the challenge token from /v1/authenticate in X-MFA-Challenge. Failed codes are counted: a wrong code reports the attempts left, and once they are exhausted a cooling-off period starts and further attempts are refused until it elapses. Branch on `code` (`otp_m.otp_invalid`, `otp_m.max_attempts_reached`, `otp_m.cooling_period_active`) rather than on the status: the TOTP branch reports a wrong code as 400 (the web middleware treats 401 as a token-refresh signal) while the email/phone branch reports it as 401, and both branches keep 429 for the two rate-limited states so the client can read the time left. The cooling-off gate fails closed: a read the server cannot complete refuses the attempt with 500 `otp_m.cache_error` on both branches rather than letting it through.
In: header
Header Parameters
Application identifier. Must be a value from the configured whitelist (e.g. web-app, admin-app, configurator-app). When provided, the refresh token cookie is scoped per application to prevent cross-app token collisions. If a whitelist is configured and the value is not in it, the request is rejected with 400.
Pre-auth MFA challenge token returned by /v1/authenticate. Required by /v1/verify-2FA when auth.2fa_challenge is enabled.
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/verify-2FA" \ -H "Content-Type: application/json" \ -d '{ "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5", "otp": "string" }'{
"access_token": "string",
"expires_in": 0,
"idle_timeout_seconds": 0,
"user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"
}{
"status": 400,
"code": "otp_m.otp_invalid",
"message": "Invalid OTP, 2 attempt(s) remaining"
}{
"status": 401,
"code": "otp_m.otp_invalid",
"message": "Invalid OTP, 2 attempt(s) remaining"
}{
"status": 429,
"code": "otp_m.max_attempts_reached",
"message": "Max attempts reached, cooling period of 1 minute(s) activated",
"retry_after": 60
}{
"status": 500,
"code": "otp_m.cache_error",
"message": "Cache operation error",
"class": "business"
}