Account registration, login, OAuth, password reset, token refresh, session lifecycle, MFA, and OAuth device-authorization for CLI/MCP clients.
GET /.well-known/openid-configuration
OpenID Connect discovery document
Alias for `/.well-known/oauth-authorization-server`. Returns the same RFC 8414 authorization server metadata. Provided for compatibility with OpenID Connect clients.
Auth
Responses
| Status | Description |
200 | Authorization server metadata document. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
GET /oauth/authorize
OAuth 2.0 authorization endpoint
Initiates the OAuth 2.0 authorization code flow with PKCE (S256 required, plain rejected per RFC 7636 §4.6). Redirects the user to the consent page on success, or returns an RFC 6749 error response.
Auth
Parameters
| Name | In | Type | Required | Description |
response_type | query | string (enum) | yes | |
client_id | query | string | yes | |
redirect_uri | query | string<uri> | yes | |
code_challenge | query | string | yes | PKCE code challenge (S256). |
code_challenge_method | query | string (enum) | no | PKCE challenge method. Only `S256` is accepted. |
state | query | string | no | |
scope | query | string | no | |
Responses
| Status | Description |
302 | Redirect to consent page or error redirect. |
400 | RFC 6749 error response for invalid requests that cannot be redirected. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /oauth/register
Dynamic client registration (RFC 7591)
Registers a new OAuth 2.0 client dynamically per RFC 7591. Returns a `client_id` for use in subsequent authorization requests.
Auth
Request Body
| Field | Type | Required | Description |
redirect_uris | array of string | yes | |
client_name | string | no | |
Responses
| Status | Description |
201 | Client registered. |
400 | RFC 7591 error response. `error` values include `invalid_redirect_uri`, `invalid_client_metadata`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /oauth/token
OAuth 2.0 token endpoint
Exchanges an authorization code for an access token using the `authorization_code` grant type. The PKCE verifier must match the challenge submitted in `/oauth/authorize`. Accepts `application/x-www-form-urlencoded` or `application/json`. **Response format is RFC 6749 style** — not the standard Backbuild envelope.
Auth
Request Body
| Field | Type | Required | Description |
grant_type | string (enum) authorization_code | yes | |
code | string | yes | |
code_verifier | string | yes | PKCE verifier. |
Responses
| Status | Description |
200 | Access token issued. RFC 6749 response. |
400 | RFC 6749 error response. `error` values include `invalid_grant`, `invalid_request`, `invalid_client`, `unsupported_grant_type`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/auth/complete-registration
Complete email-verified registration
Completes a passwordless registration flow started by `/initiate`. Verifies the code, sets the password, creates the account, and returns session tokens. May return `mfa_enrollment_required` when the org mandates MFA before granting full access. Password must meet complexity requirements and must not appear in known breach databases. Requires a Cloudflare Turnstile token.
Auth
Request Body
| Field | Type | Required | Description |
flow_id | string<uuid> | yes | |
verification_code | string | yes | |
identifier | string<email> | yes | |
password | string | yes | Password meeting complexity requirements. Must not appear in known breach databases. |
display_name | string | no | |
Responses
| Status | Description |
200 | Registration complete. Returns session tokens or `mfa_enrollment_required: true`. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfa_required | boolean | When true, the user must complete an MFA challenge. Use `mfa_challenge_token` to call `/v1/mfa/challenge/*`. |
mfa_challenge_token | string | Short-lived JWT for MFA challenge flows. Present only when `mfa_required` is true. |
mfa_enrollment_required | boolean | When true, the user must enroll an MFA method. Use `mfa_enrollment_token` to call `/v1/mfa/*` enrollment endpoints. |
mfa_enrollment_token | string | Short-lived JWT for MFA enrollment flows. Present only when `mfa_enrollment_required` is true. |
POST /v1/auth/dev/grant-test-entitlements
Grant test entitlements (dev only)
Development-only endpoint that grants test plan entitlements to the authenticated user's organization. Returns `404 NOT_FOUND` in non-dev environments.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Test entitlements granted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/auth/dev/purge-test-org
Purge test organization (dev only)
Development-only endpoint that purges the test organization and optionally specific users. Returns `404 NOT_FOUND` in non-dev environments. The caller must be authenticated and the target org must be a test organization.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
org_id | string<uuid> | yes | UUID of the test organization to purge. |
user_ids | array of string | no | Optional list of specific user UUIDs to purge. When omitted, all users in the org are purged. |
Responses
| Status | Description |
200 | Test organization purged. Returns audit summary. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/auth/device/authorize
Initiate device authorization flow
Starts the OAuth 2.0 device authorization flow (RFC 8628 adapted with PKCE). The client provides a PKCE code challenge and receives a device code, user code, and verification URI. The user visits the verification URI in a browser to authorize the device. **Note**: This endpoint returns a raw JSON object, not the standard Backbuild envelope.
Auth
Request Body
| Field | Type | Required | Description |
redirect_uri | string<uri> | yes | |
code_challenge | string | yes | PKCE S256 code challenge. |
code_challenge_method | string (enum) S256 | no | Must be `S256`. |
state | string | no | |
Responses
| Status | Description |
200 | Device authorization initiated. Raw JSON response (no envelope wrapper). |
400 | Missing or invalid `redirect_uri`, `code_challenge`, or `code_challenge_method`. Raw JSON error response. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/auth/device/complete
Approve device authorization (browser user)
Called by the authenticated browser user to approve a pending device authorization. The user enters the `user_code` displayed on the device. On success, the authorization code is minted and the device can exchange it for tokens.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
user_code | string | yes | The user code displayed on the device. |
Responses
| Status | Description |
200 | Authorization approved. Returns the authorization code and redirect URI for the device to use. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
success | boolean | |
redirect_uri | string<uri> | |
code | string | Authorization code for the device to exchange. |
state | string | |
POST /v1/auth/device/token
Exchange device authorization code for tokens
Exchanges the authorization code from the device flow for an access token (and optionally a refresh token). The PKCE verifier must match the challenge submitted in `/device/authorize`. Supports `token_type=jwt` for a full JWT session or `token_type=api_key` (default) for a long-lived opaque API key. **Response format is RFC 6749 style** (`{access_token, token_type, expires_in?, refresh_token?}`), not the standard Backbuild envelope.
Auth
Request Body
| Field | Type | Required | Description |
code | string | yes | |
code_verifier | string | yes | PKCE verifier matching the challenge from `/device/authorize`. |
grant_type | string (enum) authorization_code | yes | |
token_type | string (enum) jwtapi_key | no | Requested token type. `api_key` (default) returns a long-lived opaque key; `jwt` returns a short-lived JWT with a refresh token. |
Responses
| Status | Description |
200 | Token issued. RFC 6749 response format. |
400 | RFC 6749 error response. `error` values include `invalid_grant`, `invalid_request`, `invalid_client`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
POST /v1/auth/google-oauth
Authenticate with Google OAuth
Exchanges a Google authorization code for session tokens. Creates a new account if the email does not exist, or links/logs into an existing account. Returns `mfa_required`, `mfa_enrollment_required`, or `google_link_required` when further action is needed. An optional `mfaDeviceToken` (or array `mfaDeviceTokens` for multi-org) bypasses the MFA challenge for a remembered device.
Auth
Request Body
| Field | Type | Required | Description |
code | string | yes | Authorization code from Google. |
redirectUri | string<uri> | yes | Redirect URI used in the OAuth flow (must be in the allowlist). |
mfaDeviceToken | string | no | Optional remembered-device token to bypass MFA challenge. |
mfaDeviceTokens | array of string | no | Optional array of device tokens for multi-org remembered-device bypass. |
Responses
| Status | Description |
200 | OAuth result. One of: full session tokens, `mfa_required`, `mfa_enrollment_required`, or `google_link_required` with a `linkToken`. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfa_required | boolean | |
mfa_challenge_token | string | |
mfa_enrollment_required | boolean | |
mfa_enrollment_token | string | |
google_link_required | boolean | When true, the Google identity matches an existing account but the accounts are not yet linked. Submit `linkToken` to `/google-oauth/confirm-link` while authenticated. |
linkToken | string | Token to pass to `/google-oauth/confirm-link`. Present only when `google_link_required` is true. |
POST /v1/auth/google-oauth/confirm-link
Confirm linking Google account to existing account
Confirms that the authenticated user consents to linking their existing Backbuild account to the Google identity identified by `linkToken` (received from `/google-oauth` when `google_link_required` is returned).
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
linkToken | string | yes | Token received from `/google-oauth` when `google_link_required` is returned. |
Responses
| Status | Description |
200 | Google account successfully linked. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
linked | boolean | |
userId | string<uuid> | |
POST /v1/auth/initiate
Initiate email verification flow
Starts a passwordless registration flow by sending a verification code to the given email address. Returns a `flow_id` used in subsequent `/registration/validate` and `/complete-registration` calls. Requires a Cloudflare Turnstile token.
Auth
Request Body
| Field | Type | Required | Description |
identifier | string<email> | yes | |
identifier_type | string (enum) emailphone | no | Type of identifier. Currently only `email` is supported. |
Responses
| Status | Description |
200 | Verification email sent. Returns `flow_id` and a user-facing message. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
flow_id | string<uuid> | |
message | string | |
GET /v1/auth/landing-hint
Get login landing hint
Returns a hint for the login page based on the visitor's cookie and Origin/Referer headers. Used to detect returning users and determine whether the org has passwordless login enabled. Public endpoint; does not require authentication.
Auth
Responses
| Status | Description |
200 | Landing hint for the login UI. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
recognized | boolean | Whether the visitor appears to be a returning user. |
passwordless_enabled | boolean | Whether passwordless (passkey) login is enabled for this org. |
POST /v1/auth/login
Log in with email and password
Authenticates a user with email and password. On success returns session tokens. If the account has MFA enabled, returns `mfa_required: true` and an `mfa_challenge_token` instead of session tokens. If the account must enroll MFA, returns `mfa_enrollment_required: true` and an `mfa_enrollment_token`. An optional `mfaDeviceToken` bypasses the interactive MFA challenge for a remembered device. Requires a Cloudflare Turnstile token.
Auth
Request Body
| Field | Type | Required | Description |
email | string<email> | yes | |
password | string | yes | |
mfaDeviceToken | string | no | Optional remembered-device token to bypass interactive MFA challenge. |
Responses
| Status | Description |
200 | Login result. One of: full session tokens, `mfa_required` with challenge token, or `mfa_enrollment_required` with enrollment token. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfa_required | boolean | When true, the user must complete an MFA challenge. Use `mfa_challenge_token` to call `/v1/mfa/challenge/*`. |
mfa_challenge_token | string | Short-lived JWT for MFA challenge flows. Present only when `mfa_required` is true. |
mfa_enrollment_required | boolean | When true, the user must enroll an MFA method. Use `mfa_enrollment_token` to call `/v1/mfa/*` enrollment endpoints. |
mfa_enrollment_token | string | Short-lived JWT for MFA enrollment flows. Present only when `mfa_enrollment_required` is true. |
POST /v1/auth/logout
Log out current session
Revokes the current session's refresh token and invalidates the session. The access token remains technically valid until its short TTL expires but will fail on any endpoint that checks session state.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Session revoked. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
message | string | |
POST /v1/auth/logout-all
Log out all sessions
Revokes all active sessions for the authenticated user across all devices.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | All sessions revoked. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
message | string | |
POST /v1/auth/lookup
Look up account by email
Determines whether an email address is registered and whether passwordless (passkey) login is enabled for that account. Used by the login UI to decide which credential flow to present. Requires a valid Cloudflare Turnstile token.
Auth
Request Body
| Field | Type | Required | Description |
email | string<email> | yes | |
Responses
| Status | Description |
200 | Lookup result. `action` indicates the recommended login flow (`password`, `passkey`, `sso`, `register`). |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
action | string | Recommended login action: `password`, `passkey`, `sso`, or `register`. |
GET /v1/auth/me
Get current user identity and first-paint data
Returns the authenticated user's full identity (profile, org, roles, permissions) together with first-paint bootstrap slices fetched in parallel. This is the primary session-bootstrap endpoint called on app load.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | User identity and bootstrap data. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
id | string<uuid> | |
email | string<email> | |
displayName | string | |
orgId | string<uuid> | |
orgSlug | string | |
roles | array of string | |
permissions | array of string | |
mfaEnabled | boolean | |
envId | string<uuid> | |
POST /v1/auth/otp/create
Send a one-time password
Sends a one-time password (OTP) to the user's email for the specified purpose (`login`, `verify_email`, or `reset_password`). Rate-limited per email. Requires a Cloudflare Turnstile token.
Auth
Request Body
| Field | Type | Required | Description |
email | string<email> | yes | |
purpose | string (enum) loginverify_emailreset_password | yes | |
Responses
| Status | Description |
200 | OTP sent (or silently suppressed if the email does not exist, to prevent enumeration). |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
message | string | |
POST /v1/auth/otp/verify
Verify a one-time password
Verifies the OTP sent by `/otp/create` and, if valid, returns session tokens (for `login` purpose) or confirms email/password-reset eligibility (other purposes). Requires the caller's IP address via `CF-Connecting-IP`.
Auth
Request Body
| Field | Type | Required | Description |
email | string<email> | yes | |
code | string | yes | |
purpose | string (enum) loginverify_emailreset_password | yes | |
Responses
| Status | Description |
200 | OTP verified. Returns session tokens for `login` purpose. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfa_required | boolean | When true, the user must complete an MFA challenge. Use `mfa_challenge_token` to call `/v1/mfa/challenge/*`. |
mfa_challenge_token | string | Short-lived JWT for MFA challenge flows. Present only when `mfa_required` is true. |
mfa_enrollment_required | boolean | When true, the user must enroll an MFA method. Use `mfa_enrollment_token` to call `/v1/mfa/*` enrollment endpoints. |
mfa_enrollment_token | string | Short-lived JWT for MFA enrollment flows. Present only when `mfa_enrollment_required` is true. |
POST /v1/auth/password/change
Change password
Changes the authenticated user's password. For accounts with an existing password, `old_password` is required (omit for initial password set). Requires a recent MFA step-up. On success, revokes all other sessions.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
old_password | string | no | Current password. Required unless this is an initial password set. |
new_password | string | yes | New password meeting complexity requirements. |
Responses
| Status | Description |
200 | Password changed. All other sessions revoked. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
was_initial_set | boolean | True if this was the first password set (no old password existed). |
sessions_revoked | integer | Number of other sessions that were revoked. |
POST /v1/auth/password/reset
Reset password with code
Resets the user's password using the code sent to their email by `/password/reset/request`. The new password must meet complexity requirements and must not appear in known breach databases.
Auth
Request Body
| Field | Type | Required | Description |
email | string<email> | yes | |
code | string | yes | |
new_password | string | yes | New password meeting complexity requirements. Must not appear in known breach databases. |
Responses
| Status | Description |
200 | Password successfully reset. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
message | string | |
POST /v1/auth/password/reset/request
Request a password reset
Sends a password-reset code to the email address if it is registered. Always returns success to prevent email enumeration. Requires a Cloudflare Turnstile token.
Auth
Request Body
| Field | Type | Required | Description |
identifier | string<email> | yes | |
Responses
| Status | Description |
200 | Reset email dispatched (or silently suppressed for unknown emails). |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
message | string | |
POST /v1/auth/preferences/passkey-primary-override
Override passkey-primary login preference
Sets the authenticated user's passkey-primary login preference to `inherit` (follow org policy), `force_on` (always prompt passkey first), or `force_off` (always show password form first).
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
override | string (enum) inheritforce_onforce_off | yes | |
Responses
| Status | Description |
200 | Preference saved. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
override | string (enum) inheritforce_onforce_off | |
POST /v1/auth/refresh
Refresh session tokens
Exchanges a valid refresh token for a new access token / refresh token pair. The old refresh token is invalidated (rotation). Returns `AUTH_REFRESH_TOKEN_INVALID` if the token has been revoked, already rotated, or is expired.
Auth
Request Body
| Field | Type | Required | Description |
refreshToken | string | yes | |
Responses
| Status | Description |
200 | New token pair issued. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | Short-lived JWT access token. |
refreshToken | string | Long-lived opaque refresh token. |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
POST /v1/auth/register
Register a new account
Creates a new user account with email and password. Returns session tokens on success, or an `mfa_enrollment_required` flag when MFA enrollment is mandatory. Requires a Cloudflare Turnstile token. Password must meet complexity requirements (uppercase, lowercase, digit, special character) and must not appear in known breach databases.
Auth
Request Body
| Field | Type | Required | Description |
email | string<email> | yes | |
password | string | yes | Password meeting complexity requirements: uppercase, lowercase, digit, and special character. Must not appear in known breach databases. |
displayName | string | no | |
orgId | string<uuid> | no | Optional organization to join upon registration. |
Responses
| Status | Description |
200 | Registration succeeded. Returns session tokens, or `mfa_enrollment_required: true` when the org requires MFA enrollment before access is granted. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfa_required | boolean | When true, the user must complete an MFA challenge. Use `mfa_challenge_token` to call `/v1/mfa/challenge/*`. |
mfa_challenge_token | string | Short-lived JWT for MFA challenge flows. Present only when `mfa_required` is true. |
mfa_enrollment_required | boolean | When true, the user must enroll an MFA method. Use `mfa_enrollment_token` to call `/v1/mfa/*` enrollment endpoints. |
mfa_enrollment_token | string | Short-lived JWT for MFA enrollment flows. Present only when `mfa_enrollment_required` is true. |
POST /v1/auth/registration/validate
Validate registration verification code
Validates the verification code for an in-progress registration flow without completing it. Used to give inline feedback before the user fills in the rest of the registration form.
Auth
Request Body
| Field | Type | Required | Description |
flow_id | string<uuid> | yes | |
verification_code | string | yes | |
identifier | string<email> | yes | |
Responses
| Status | Description |
200 | Code is valid for the given flow. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
410 | Flow expired or code is invalid. Error code: `NOT_FOUND` or `VALIDATION_ERROR`. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
validated | boolean | Always `true` on success. |
POST /v1/auth/switch-env
Switch active environment
Issues new session tokens scoped to the specified environment within the current organization.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
env_id | string<uuid> | yes | |
Responses
| Status | Description |
200 | New env-scoped token pair issued. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | Short-lived JWT access token. |
refreshToken | string | Long-lived opaque refresh token. |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
POST /v1/auth/switch-org
Switch active organization
Issues new session tokens scoped to the specified organization. The caller must be a member of the target org.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
org_id | string<uuid> | yes | |
Responses
| Status | Description |
200 | New org-scoped token pair issued. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
403 | 403 Forbidden — authenticated but lacking the required membership, role, permission, MFA step-up, or feature entitlement. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | Short-lived JWT access token. |
refreshToken | string | Long-lived opaque refresh token. |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
POST /v1/auth/webauthn/assertion/options
Get WebAuthn assertion options for passkey login
Returns WebAuthn assertion (get) options for the primary passkey login flow. Returns an `assertion_nonce` that must be submitted with the credential in `/webauthn/assertion/verify`.
Auth
Responses
| Status | Description |
200 | WebAuthn assertion options and nonce. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
options | object | WebAuthn PublicKeyCredentialRequestOptions. |
assertion_nonce | string | Nonce to submit alongside the credential in `/webauthn/assertion/verify`. |
POST /v1/auth/webauthn/assertion/verify
Verify WebAuthn assertion for passkey login
Verifies a WebAuthn assertion credential against the stored passkey and the nonce issued by `/webauthn/assertion/options`. On success returns session tokens.
Auth
Request Body
| Field | Type | Required | Description |
assertion_nonce | string | yes | |
credential | object | yes | WebAuthn PublicKeyCredential assertion. |
Responses
| Status | Description |
200 | Passkey verified. Returns session tokens. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | Short-lived JWT access token. |
refreshToken | string | Long-lived opaque refresh token. |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
POST /v1/mfa/challenge/email-otp/send
Send email OTP during MFA challenge
Sends an email OTP to the user's registered email address during an active MFA challenge. Requires an MFA challenge token.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | OTP sent. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
429 | 429 Too Many Requests — a rate limit or usage quota was exceeded. Retry after the indicated window. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
sent | boolean | |
email | string | Masked email address (e.g. `u***@example.com`). |
expiresInMinutes | integer | |
POST /v1/mfa/challenge/email-otp/verify
Verify email OTP during MFA challenge
Verifies the email OTP sent by `/challenge/email-otp/send` during an active MFA challenge. Requires an MFA challenge token. On success returns full session tokens and optionally a device trust token.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | |
rememberDevice | boolean | no | |
rememberDeviceDays | integer | no | |
deviceName | string | no | |
Responses
| Status | Description |
200 | MFA verified. Returns session tokens and optionally a device trust token. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfaDeviceToken | string | Device trust token for remembered-device bypass on future logins. Present only when `rememberDevice` was requested. |
POST /v1/mfa/challenge/recovery
Use recovery code during MFA challenge
Verifies a one-time recovery code during an active MFA challenge. The code is consumed and cannot be reused. Requires an MFA challenge token. On success returns full session tokens and optionally a device trust token.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | |
rememberDevice | boolean | no | |
rememberDeviceDays | integer | no | |
deviceName | string | no | |
Responses
| Status | Description |
200 | Recovery code accepted. Returns session tokens. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfaDeviceToken | string | Device trust token for remembered-device bypass on future logins. Present only when `rememberDevice` was requested. |
POST /v1/mfa/challenge/totp
Verify TOTP during MFA challenge
Verifies a TOTP code during an active MFA challenge (mid-login). Requires an MFA challenge token issued by `/login`, `/google-oauth`, or similar. On success, returns full session tokens. Optionally issues a `mfaDeviceToken` for remembered-device bypass on future logins.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | 6-digit TOTP code. |
rememberDevice | boolean | no | |
rememberDeviceDays | integer | no | |
deviceName | string | no | |
Responses
| Status | Description |
200 | MFA verified. Returns session tokens and optionally a device trust token. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfaDeviceToken | string | Device trust token for remembered-device bypass on future logins. Present only when `rememberDevice` was requested. |
POST /v1/mfa/challenge/webauthn/options
Get WebAuthn options during MFA challenge
Returns WebAuthn assertion options and a `challenge_token` during an active MFA challenge. Requires an MFA challenge token.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | WebAuthn assertion options for the MFA challenge. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
options | object | WebAuthn PublicKeyCredentialRequestOptions or CreationOptions. |
challenge_token | string | HMAC-signed JWT challenge to submit with the credential verify call. |
POST /v1/mfa/challenge/webauthn/verify
Verify WebAuthn assertion during MFA challenge
Verifies a WebAuthn assertion during an active MFA challenge. Requires an MFA challenge token. On success returns full session tokens and optionally a device trust token.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
credential | object | no | WebAuthn PublicKeyCredential assertion. |
id | string | no | |
rawId | string | no | |
type | string | no | |
response | object | no | |
challenge_token | string | no | |
rememberDevice | boolean | no | |
rememberDeviceDays | integer | no | |
deviceName | string | no | Truncated to 100 characters server-side. |
Responses
| Status | Description |
200 | MFA verified. Returns session tokens and optionally a device trust token. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | |
refreshToken | string | |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
mfaDeviceToken | string | Device trust token for remembered-device bypass on future logins. Present only when `rememberDevice` was requested. |
POST /v1/mfa/email-otp/setup
Set up email OTP MFA method
Enrolls the user's verified email address as an MFA method and sends a verification OTP. Returns recovery codes on first enrollment. Accepts either a full session JWT or an MFA enrollment token.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Email OTP method enrolled. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
methodId | string<uuid> | |
email | string<email> | |
isFirstMethod | boolean | |
recoveryCodes | array of string | |
session | object | Session token pair. |
GET /v1/mfa/methods
List enrolled MFA methods
Returns all MFA methods enrolled for the authenticated user. Accepts either a full session JWT or an MFA enrollment token (issued during login when MFA enrollment is required).
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | List of enrolled MFA methods. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
methods | array of object | |
PATCH /v1/mfa/methods/{methodId}
Rename an MFA method
Updates the display name of an enrolled MFA method.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
methodId | path | string<uuid> | yes | UUID of the MFA method to rename. |
Request Body
| Field | Type | Required | Description |
name | string | yes | |
Responses
| Status | Description |
200 | Method renamed. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
methodId | string<uuid> | |
name | string | |
renamedAt | string<date-time> | |
DELETE /v1/mfa/methods/{methodId}
Delete an MFA method
Removes an enrolled MFA method. When `force=true` is passed, requires a recent authentication and MFA step-up. Passing `force` without a recent step-up returns `MFA_STEPUP_REQUIRED`.
Auth Session JWT (Bearer)
Parameters
| Name | In | Type | Required | Description |
methodId | path | string<uuid> | yes | UUID of the MFA method to delete. |
force | query | boolean | no | When true, requires a recent MFA step-up and deletes even the last method (fully disenrolling MFA). |
Responses
| Status | Description |
200 | Method deleted. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
404 | 404 Not Found — the requested resource does not exist or is not visible to the caller. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
methodId | string<uuid> | |
remainingMethods | integer | |
mfaDisenrolled | boolean | True if all MFA methods have been removed. |
POST /v1/mfa/recovery-codes/generate
Generate new recovery codes
Generates a fresh set of one-time recovery codes, invalidating any previously issued codes. The returned codes are shown only once.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | New recovery codes issued. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
codes | array of string | |
count | integer | |
warning | string | Advisory message reminding the user to store codes safely. |
GET /v1/mfa/step-up/methods
List available step-up MFA methods
Returns the list of MFA method types available for step-up authentication for the current user.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | Available step-up method types. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
methods | array of string | Array of method type strings, e.g. `["totp", "webauthn"]`. |
POST /v1/mfa/step-up/totp
Perform TOTP step-up
Verifies a TOTP code to elevate the current session to MFA-stepped-up status. Returns a new token pair with the step-up claim. Required before sensitive operations such as password change. Only the `code` field is accepted; device-remember fields do not apply to step-up.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | 6-digit TOTP code from the authenticator app. |
Responses
| Status | Description |
200 | Step-up successful. Returns new token pair. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | Short-lived JWT access token. |
refreshToken | string | Long-lived opaque refresh token. |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
POST /v1/mfa/step-up/webauthn/options
Get WebAuthn options for step-up
Returns WebAuthn assertion options and an HMAC-signed `challenge_token` for step-up authentication.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | WebAuthn assertion options and challenge token for step-up. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
options | object | WebAuthn PublicKeyCredentialRequestOptions or CreationOptions. |
challenge_token | string | HMAC-signed JWT challenge to submit with the credential verify call. |
POST /v1/mfa/step-up/webauthn/verify
Verify WebAuthn assertion for step-up
Verifies a WebAuthn assertion for step-up and returns a new token pair with the step-up claim.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
credential | object | no | WebAuthn PublicKeyCredential assertion. |
challenge_token | string | no | |
rememberDevice | boolean | no | |
rememberDeviceDays | integer | no | |
deviceName | string | no | Truncated to 100 characters server-side. |
Responses
| Status | Description |
200 | Step-up successful. Returns new token pair. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
accessToken | string | Short-lived JWT access token. |
refreshToken | string | Long-lived opaque refresh token. |
accessTokenExpiresAt | string<date-time> | |
refreshTokenExpiresAt | string<date-time> | |
POST /v1/mfa/totp/confirm
Confirm TOTP enrollment
Verifies the first TOTP code against the encrypted secret from `/totp/setup`, completing TOTP enrollment. Returns recovery codes on first enrollment. If this is the first MFA method, also returns a full session (completing login when enrollment was required). Accepts either a full session JWT or an MFA enrollment token.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
code | string | yes | 6-digit TOTP code. |
methodId | string<uuid> | yes | |
encryptedSecret | string | yes | |
Responses
| Status | Description |
200 | TOTP enrolled. `recoveryCodes` present if this is the first method enrolled. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
verified | boolean | |
methodId | string<uuid> | |
isFirstMethod | boolean | |
recoveryCodes | array of string | One-time recovery codes. Only present when this is the first MFA method enrolled. |
session | object | Session token pair. |
POST /v1/mfa/totp/setup
Set up TOTP MFA method
Generates a TOTP secret and URI for enrollment. The returned `encryptedSecret` must be submitted along with the first TOTP code to `/totp/confirm` to complete enrollment. Accepts either a full session JWT or an MFA enrollment token.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
friendlyName | string | no | |
Responses
| Status | Description |
200 | TOTP setup initiated. Scan the URI with an authenticator app, then confirm with `/totp/confirm`. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
409 | 409 Conflict — the request conflicts with an existing resource or current state (unique constraint, optimistic-lock, duplicate). |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
methodId | string<uuid> | |
secret | string | Base32-encoded TOTP secret for manual entry. |
uri | string | otpauth:// URI for QR code generation. |
encryptedSecret | string | Encrypted secret to submit to `/totp/confirm`. |
session | object | Session token pair. |
POST /v1/mfa/webauthn/register/options
Get WebAuthn registration options for MFA enrollment
Returns WebAuthn attestation (create) options and a `challenge_token` for enrolling a security key or platform authenticator as an MFA method. Accepts either a full session JWT or an MFA enrollment token.
Auth Session JWT (Bearer)
Responses
| Status | Description |
200 | WebAuthn registration options and challenge token. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
options | object | WebAuthn PublicKeyCredentialRequestOptions or CreationOptions. |
challenge_token | string | HMAC-signed JWT challenge to submit with the credential verify call. |
POST /v1/mfa/webauthn/register/verify
Verify WebAuthn registration for MFA enrollment
Verifies the attestation response from the authenticator and stores the credential as an MFA method. Returns recovery codes on first enrollment. If this is the first MFA method and enrollment was required, also returns a full session. Accepts either a full session JWT or an MFA enrollment token.
Auth Session JWT (Bearer)
Request Body
| Field | Type | Required | Description |
attestationResponse | object | yes | |
Responses
| Status | Description |
200 | WebAuthn credential enrolled. |
400 | 400 Bad Request — a request parameter, body field, or the JSON body itself failed validation. |
401 | 401 Unauthorized — missing, expired, malformed, or revoked credentials. |
500 | 500 Internal Server Error — an unexpected server-side error. The message is sanitized; the correlation id is logged server-side. |
200 response body: data fields
| Field | Type | Description |
verified | boolean | |
methodId | string<uuid> | |
isFirstMethod | boolean | |
recoveryCodes | array of string | One-time recovery codes. Only present when this is the first MFA method enrolled. |
session | object | Session token pair. |