POST /v1/auth/mfa/verify
Stamp a "recently MFA-verified" assertion on the caller's session. The step-up middleware reads this back on subsequent sensitive operations to confirm the user proved a second factor recently.
::: tip Auth Required: cookie or Bearer. Must be a browser session (not an API key). :::
Request
POST /v1/auth/mfa/verify
| Header | Required | Notes |
|---|---|---|
Cookie: identsphere_at=... OR Authorization: Bearer ... | yes | — |
Content-Type: application/json | yes | — |
Body
{ "code": "123456" }
| Field | Type | Required | Notes |
|---|---|---|---|
code | string | yes | 6–8 chars. The current TOTP code. Recovery codes are NOT accepted here — they're for account recovery at sign-in time. |
Response
200 OK
{
"verified": true,
"verified_at": 1748448000,
"expires_in": 1800
}
| Field | Type | Notes |
|---|---|---|
verified | bool | Always true on 2xx. |
verified_at | int | Unix timestamp at which verification was recorded. |
expires_in | int | Seconds until the step-up assertion expires (default 1800, configurable via step_up_ttl_secs). |
Error responses
| Status | Code | When |
|---|---|---|
| 400 | invalid_input | Code missing or wrong length. |
| 401 | authentication_required | Code doesn't validate against the stored TOTP secret. |
| 403 | forbidden | Caller is not a browser session (e.g. API key), OR MFA isn't enabled for this user. |
| 404 | not_found | User no longer exists. |
| 500 | internal_error | TOTP build or storage failure. |
Example: curl
curl -X POST https://auth.example.com/v1/auth/mfa/verify \
-H 'Content-Type: application/json' \
-b cookies.txt \
-d '{"code":"123456"}'
Example: TypeScript (@identsphere/react)
import { useMfaVerify } from '@identsphere/react';
function StepUpModal({ onSuccess }: { onSuccess: () => void }) {
const verify = useMfaVerify();
return (
<form onSubmit={async (e) => {
e.preventDefault();
const code = new FormData(e.currentTarget).get('code') as string;
await verify.mutateAsync({ code });
onSuccess();
}}>
<input name="code" placeholder="123456" />
<button type="submit">Verify</button>
</form>
);
}
Notes
- This endpoint is for step-up authentication — proving the user is
still in front of the screen before a sensitive operation. It is NOT the
same as the initial login MFA challenge (that's
/v1/auth/mfa/challenge). - The assertion is keyed by
session_family_id. Other sessions belonging to the same user are unaffected. - An audit entry (
auth.mfa.step_up) is recorded. - The default step-up TTL is 30 minutes; tune it via
AppConfig::step_up_ttl_secs.