CorebanqCorebanq Developer Docs
Authv1Authentication

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.

POST
/v1/verify-2FA

Authorization

AuthorizationBearer <token>

In: header

Header Parameters

X-App-ID?string

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.

X-MFA-Challenge?string

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"
}