Verify MFA
Second step of an MFA-protected login. Call this only after /auth/login returns mfa_required: true: send the mfa_challenge_token from that response plus the code from the user's authenticator app, and you get the same session token /auth/login returns for an account without MFA. The SSO callback issues the same kind of challenge when a user who signed in through their identity provider also has MFA on.
The challenge is valid for 5 minutes and is used up by a successful verification; a wrong code doesn't use it up, so the user can try again. Older clients may instead re-send username + password with the code; that form still works and counts against the sign-in attempt limit.
Attempt limit: each user gets 5 code checks per sliding hour, right or wrong. The limit is shared with the other MFA code checks: /mfa/activate, /mfa/verify, /mfa/disable, /mfa/backup-codes/regenerate and step-up re-authentication. Past it the API answers 429 with the minutes until the oldest check leaves the window.
Request body
/auth/login (or SSO callback) response. Required unless you send username + password.mfa_challenge_token: the same credentials as the /auth/login call, re-verified on this request.Unknown fields are rejected with 400 (strict decoding).
Response (200 OK)
true on a successful verification.Authorization: Bearer <token>.uuid, username, email, role. (It also carries the legacy integer id until the sunset; don't use it.)Errors
Errors are JSON: {"error": "<message>", "code": "<CODE>"}.
token ("Token is required"), neither a challenge nor username + password, unknown fields, or MFA_NOT_ENABLED (the user has no MFA set up).MFA_INVALID_TOKEN — wrong or already-used code ("Invalid authentication code. Please try again."). MFA_CHALLENGE_INVALID — the challenge is unknown, used or older than 5 minutes ("Your sign-in session expired. Please sign in again."); sign in again. INVALID_CREDENTIALS — legacy form only, wrong username or password.EMAIL_NOT_VERIFIED — the user hasn't verified their email; the body also carries user_uuid and a one-time resend_token, as on /auth/login. SSO_REQUIRED — the user's account enforces SSO, so a password sign-in (legacy form or a password challenge) is refused.MFA_RATE_LIMITED — the user used their 5 code checks for the hour ("Too many attempts. Try again in N minutes."). The legacy form can also hit the sign-in attempt limit, with a Retry-After header.SSO_CHECK_UNAVAILABLE — the SSO enforcement check couldn't run; retry.