Authentication
Endpoints for account registration, login, OAuth, password management, and session lifecycle. All request and response bodies are JSON.
Response Envelope
Every endpoint returns the same envelope. Successful responses set
success: true and carry the payload under data:
{
"success": true,
"data": { /* endpoint-specific payload */ }
}
Failed responses set success: false and carry a machine-readable
code and a human-readable message under
error:
{
"success": false,
"error": {
"code": "AUTH_INVALID_CREDENTIALS",
"message": "Invalid email or password"
}
} Register
POST /v1/auth/register
Create a new account with an email and password. This endpoint provisions
the account and dispatches a verification email; it does
not return access or refresh tokens. To prevent account
enumeration, the response is the same generic message whether or not the
email is already registered. Treat the generic message as success and direct
the user to check their inbox. displayName and
orgId are optional.
Request Body
{
"email": "user@example.com",
"password": "your-password",
"displayName": "Jane Smith"
} Response
{
"success": true,
"data": {
"message": "If this email is not already registered, check your inbox for a verification link."
}
}
Passwords must satisfy the platform policy (minimum length plus at least one
uppercase letter, lowercase letter, digit, and special character). A
password that fails policy, or one that appears in a known breach
corpus, is rejected with a 400 and a specific code such
as WEAK_PASSWORD or BREACHED_PASSWORD. These
password errors are safe to surface because they do not reveal whether the
email exists.
Email-Verified Sign-Up
Backbuild also offers a code-based sign-up flow. Start it with
/v1/auth/initiate to email a one-time verification code and
obtain a flow_id, optionally check the code with
/v1/auth/registration/validate, then redeem it and set the
password with /v1/auth/complete-registration.
Initiate
POST /v1/auth/initiate
Emails a one-time verification code and returns a flow_id. The
response is intentionally uniform regardless of whether the email belongs to
a new or returning user, so it never reveals account existence.
identifier_type is optional and defaults to email.
Request Body
{
"identifier": "user@example.com"
} Response
{
"success": true,
"data": {
"flow_id": "...",
"message": "Check your email for a verification code"
}
} Validate Code
POST /v1/auth/registration/validate
Optionally verify that a code is valid for a flow before completing
registration (for example, to advance a multi-step form). It does not issue
tokens. An invalid code returns 401; an expired or consumed
flow returns 410.
Request Body
{
"flow_id": "...",
"identifier": "user@example.com",
"verification_code": "123456"
} Complete Registration
POST /v1/auth/complete-registration
Redeems the emailed verification code, sets the account password, and (when
no further factor is required) returns the session tokens.
display_name is optional.
Request Body
{
"flow_id": "...",
"identifier": "user@example.com",
"verification_code": "123456",
"password": "your-password",
"display_name": "Jane Smith"
} Response
{
"success": true,
"data": {
"tokens": {
"access_token": "eyJ...",
"refresh_token": "eyJ...",
"expires_in": 900,
"token_type": "Bearer"
},
"user_id": "..."
}
}
If the account requires multi-factor authentication, the response instead
carries mfa_required with an mfa_challenge_token
(and the available mfa_methods), or
mfa_enrollment_required with an mfa_enrollment_token,
rather than session tokens. Complete the MFA step before tokens are issued.
Login
POST /v1/auth/login
Authenticate with email and password. On success, returns access and refresh
tokens. An invalid email or password returns a generic 401 with
code AUTH_INVALID_CREDENTIALS; the response never reveals
whether the email exists or whether the account is locked.
Request Body
{
"email": "user@example.com",
"password": "your-password"
} Response
{
"success": true,
"data": {
"success": true,
"userId": "...",
"email": "user@example.com",
"displayName": "Jane Smith",
"orgId": "...",
"sessionId": "...",
"accessToken": "eyJ...",
"refreshToken": "eyJ...",
"accessTokenExpiresAt": "...",
"refreshTokenExpiresAt": "..."
}
}
When the account has MFA enabled or pending enrollment, the response instead
carries mfaRequired (with mfaChallengeToken and
mfaMethods) or mfaEnrollmentRequired (with
mfaEnrollmentToken) rather than access and refresh tokens.
Refresh Token
POST /v1/auth/refresh Exchange a refresh token for a fresh access token. Refresh tokens are rotated, so each call invalidates the refresh token it consumes.
Request Body
{
"refreshToken": "eyJ..."
}
The response carries the same shape as the login response: a fresh
accessToken and rotated refreshToken. An invalid or
expired refresh token returns 401 with code
AUTH_REFRESH_TOKEN_INVALID.
Logout
POST /v1/auth/logout Revoke the current session. Requires a valid access token.
POST /v1/auth/logout-all Revoke every active session for the authenticated user across all devices. Requires a valid access token.
Google OAuth
POST /v1/auth/google-oauth
Sign in or sign up with a Google authorization code. Exchange the
code obtained from Google together with the
redirectUri used to obtain it. If the Google account email
matches an existing password account that is not yet linked, the response
indicates that account linking is required (googleLinkRequired,
with a short-lived linkToken). As with email login, the
response may instead carry an MFA challenge or enrollment requirement.
Request Body
{
"code": "4/0Adeu5...",
"redirectUri": "https://app.backbuild.ai/auth/google/oauth"
} POST /v1/auth/google-oauth/confirm-link
Consent to linking the Google identity to the existing matching account.
Requires the caller to be authenticated as that local account and to present
the linkToken returned by the prior
/v1/auth/google-oauth call.
One-Time Codes
POST /v1/auth/otp/create
Request a one-time code by email. purpose is one of
login, verify_email, or
reset_password. The response is always a generic message so it
never reveals whether the email is registered.
Request Body
{
"email": "user@example.com",
"purpose": "login"
} POST /v1/auth/otp/verify
Verify a one-time code. purpose must match the value used to
create the code. An invalid or expired code returns 401.
Request Body
{
"email": "user@example.com",
"code": "123456",
"purpose": "login"
} Password Reset
Request Reset
POST /v1/auth/password/reset/request Request Body
{
"identifier": "user@example.com"
} Sends a password reset code by email. The response is a fixed generic message regardless of whether an account exists for the address, so it cannot be used to enumerate accounts.
Complete Reset
POST /v1/auth/password/reset Request Body
{
"email": "user@example.com",
"code": "123456",
"new_password": "new-secure-password"
} Verifies the emailed code and sets a new password. The new password must satisfy the platform password policy.
Change Password
POST /v1/auth/password/change Change the password for the authenticated user (also used by OAuth-only users to set a password for the first time). Requires a valid access token and a recently completed multi-factor step; if the session’s MFA is stale the request is rejected and the client must re-complete an MFA ceremony first.
Request Body
{
"old_password": "current-password",
"new_password": "new-secure-password"
} Passwordless (Passkey) Sign-In
POST /v1/auth/webauthn/assertion/options
Begin a passwordless WebAuthn sign-in. Returns the assertion request
options and an assertion_nonce to echo back on
verify.
POST /v1/auth/webauthn/assertion/verify
Complete the WebAuthn ceremony by submitting the authenticator
credential together with the assertion_nonce. On
success, and when passkey-as-primary sign-in is enabled for the
account, the response issues access and refresh tokens just like a
password login.
Device Authorization (CLI & Agents)
Command-line tools and agents authenticate with an OAuth 2.0 Authorization Code flow with PKCE (RFC 7636, S256 only). The tool opens an authorization URL in a browser; once the user approves in their logged-in session, the tool exchanges the resulting code (with its PKCE verifier) for tokens.
POST /v1/auth/device/authorize
Start the flow. Send a localhost redirect_uri, a PKCE
code_challenge (S256), and an opaque state. Returns
an authorization URL for the user to open in a browser.
POST /v1/auth/device/complete Called by the logged-in browser session (authenticated) to approve the pending device request.
POST /v1/auth/device/token
Exchange the authorization code together with the PKCE
code_verifier for access and refresh tokens after the user
completes browser-based auth.
Handling Challenges & Errors
Beyond per-endpoint validation errors, integrators should handle the following responses, which can occur on the identity endpoints above.
Proof-of-Human Challenge (401)
Identity endpoints (register, complete-registration, initiate, login, one-time-code creation, and password-reset requests) may require a Cloudflare Turnstile proof-of-human token; automated or high-volume traffic is more likely to be challenged. When a token is required and is missing or invalid, the API responds with HTTP 401 and a flat body:
{
"error": "turnstile_required",
"message": "This endpoint requires a Cloudflare Turnstile challenge"
}
On this response, render a
Cloudflare
Turnstile widget, obtain a token, and resubmit the same request with the
token supplied either as the request header
cf-turnstile-response or as the JSON body field
turnstileToken (the body fields turnstile_token and
cf-turnstile-response are also accepted).
Rate Limiting (429)
Requests may be rate limited and receive HTTP 429. When a
Retry-After header is present, honor it and back off for the
indicated number of seconds before retrying. Build clients to back off and
retry rather than to loop immediately.
Region Restrictions (451)
Requests originating from embargoed or sanctioned regions receive HTTP 451 for sanctions-compliance reasons. This is not retryable from the affected region.
Access Denied (403)
Requests from blocked sources (blacklisted IPs and anonymizing VPN exit nodes) receive HTTP 403. Browser calls are additionally governed by a CORS allowlist, so only approved web origins can read API responses from a browser context.
Token Format
Access tokens are short-lived bearer tokens (presented as
Authorization: Bearer <token>); refresh tokens have a
longer lifetime and are rotated, so each refresh invalidates the previous
refresh token. Tokens are scoped to the user, the active organization, and
that organization’s role. Use accessTokenExpiresAt and
refreshTokenExpiresAt (or the expires_in seconds
returned by complete-registration) to know when to refresh.