Skip to content
LogoLogo

Authentication

Browser-session and native OAuth credential lifecycle operations.

Create an account

POST/api/v1/auth/register

Creates a user and password credential, then issues an account-only browser session. No Workspace is created during registration. The caller must create their first Workspace through POST /api/v1/workspaces/bootstrap before using Workspace-scoped operations, or accept a Workspace invitation. Without invitation_token, the address starts unverified and a verification message is sent. A valid pending invitation for the supplied email verifies that address without a second email. Registration does not consume the invitation or grant membership; accepting it remains a separate explicit action. Invalid, expired, revoked, used or mismatched invitation credentials return 400 invalid_invitation without creating an account.

Verification gates account recovery, not access: a password reset is never issued for an unverified address, because whoever controls that inbox has not proven they own the account.

A taken address is reported plainly. Registration necessarily reveals whether an address can be registered, so a vague failure would only strand a user who already has an account.

Request Body

application/json
emailRequired
string <email>·min 3·max 320

Normalized to lowercase and trimmed before storage and comparison.

passwordRequired
string <password>·min 12·max 128

Between 12 and 128 characters. There are deliberately no composition rules: length and non-reuse resist guessing, while character-class rules mostly produce predictable substitutions. Passwords appearing in a known breach corpus are refused.

display_name
string·min 1·max 100

Optional. When omitted, a starting name is derived from the local part of the address; it is a default the user can change, not an identity claim.

invitation_token
string·min 1·max 512

Optional pending Workspace invitation credential delivered to this email address. Proves mailbox control without a separate verification email. Does not consume the invitation or grant membership.

Responses

Sign in with an email address and password

POST/api/v1/auth/login

Verifies the password. When the account has no second factor this issues a browser session directly. When it does, the response instead carries a short-lived challenge and no session is created: the caller must complete verifyMFA before anything is readable.

Both outcomes are 200, and the two bodies are told apart by the mfa_required field. A client must branch on it rather than assuming a session exists.

Every failure returns the same 401 invalid_credentials whatever went wrong — unknown address, no password credential on the account, or a wrong password — and the server spends comparable time in each case. Distinguishing them would turn this endpoint into an oracle for which addresses are registered.

Request Body

application/json
emailRequired
string <email>·min 3·max 320

Normalized to lowercase and trimmed before storage and comparison.

passwordRequired
string <password>·min 12·max 128

Between 12 and 128 characters. There are deliberately no composition rules: length and non-reuse resist guessing, while character-class rules mostly produce predictable substitutions. Passwords appearing in a known breach corpus are refused.

remember_me
boolean

Whether to remember this device. true (the default when omitted, which preserves earlier client behavior) issues a persistent session cookie with the 7-day idle and 30-day absolute lifetimes. false issues a browser-session cookie that the browser discards when it closes, and the server bounds the session to 48 hours, idle and absolute.

Responses

Verify an email address

POST/api/v1/auth/email/verify

Redeems the single-use token carried by the verification email link. Redemption is atomic, so a replayed link fails rather than verifying twice, and an expired or unknown token is refused identically to a spent one.

Request Body

application/json
tokenRequired
string·min 1·max 512

A single-use, expiring bearer secret delivered by email. Only its hash is stored, so it cannot be recovered from a database disclosure. Treat it as a credential: never log it or place it in a URL you retain.

Responses

Send a new verification message

POST/api/v1/auth/email/resend-verification

Issues a fresh verification token and retires any outstanding one, so a link forwarded from an older message stops working.

The response is 202 and empty whether or not the address is registered, whether or not it is already verified, and whether or not delivery succeeded. Anything else would confirm an address exists.

Request Body

application/json
emailRequired
string <email>·min 3·max 320

Normalized to lowercase and trimmed before storage and comparison.

Responses

Request a password reset

POST/api/v1/auth/password/forgot

Issues a single-use reset token to a verified address, retires any outstanding one, and emails a link to /reset-password carrying the token. The link is valid for four hours. No reset token is issued for an unverified address: whoever controls that inbox has not proven they own the account. Instead, Assign sends a fresh verification email link so the account holder can verify the address and then request a reset.

Like resend-verification, the response is 202 and empty in every case, including delivery failure.

Request Body

application/json
emailRequired
string <email>·min 3·max 320

Normalized to lowercase and trimmed before storage and comparison.

Responses

Reset a password with a token

POST/api/v1/auth/password/reset

Redeems a single-use reset token and replaces the password.

A reset revokes every session for the account, including the one making the request: a reset is what an account-takeover victim performs, so the attacker's session must not survive it, and the holder of a mailed token has not otherwise authenticated. Both browser-session cookies are expired in the response.

Request Body

application/json
tokenRequired
string·min 1·max 512

A single-use, expiring bearer secret delivered by email. Only its hash is stored, so it cannot be recovered from a database disclosure. Treat it as a credential: never log it or place it in a URL you retain.

passwordRequired
string <password>·min 12·max 128

Between 12 and 128 characters. There are deliberately no composition rules: length and non-reuse resist guessing, while character-class rules mostly produce predictable substitutions. Passwords appearing in a known breach corpus are refused.

Responses

Change the current user's password

POST/api/v1/auth/password/change

Replaces the password for the authenticated user. The current password is required: an unattended browser must not be enough to lock the owner out.

Unlike a reset, a change keeps the session that performed it and revokes every other session, so the user is not signed out of the browser they are using.

An account that signs in only through an identity provider has no password to change and receives 409.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
current_passwordRequired
string <password>·min 1·max 128
new_passwordRequired
string <password>·min 12·max 128

Between 12 and 128 characters. There are deliberately no composition rules: length and non-reuse resist guessing, while character-class rules mostly produce predictable substitutions. Passwords appearing in a known breach corpus are refused.

Responses

Start a passkey sign-in

POST/api/v1/auth/passkeys/login/options

Returns the options to pass to navigator.credentials.get(), together with a single-use ceremony token to return with the assertion.

The ceremony is discoverable: it names no account and lists no allowed credentials, because the authenticator is what proposes an account. That is what makes passkey sign-in usernameless, and it is also why this unauthenticated endpoint cannot be used to ask whether a given credential or account exists — the response is the same for every caller.

Passkey operations are served only by a deployment with a configured relying party. Where none is configured they return 404, like any other unrouted path.

Responses

Complete a passkey sign-in

POST/api/v1/auth/passkeys/login/verify

Verifies the authenticator's assertion and issues a browser session.

No second factor is requested. A passkey is strong authentication on its own — the authenticator performed user verification, which is the assurance a second factor exists to add — so unlike a password sign-in this never returns a challenge. A successful response is always the account.

Every failure is 401, whether the ceremony was unknown, expired, or already used, or the assertion did not verify. The distinctions are useful only to someone probing the endpoint; an honest client can only start a new ceremony.

A credential whose signature counter fails to advance is treated as cloned: it is disabled, and this and every later attempt with it are refused. The account's other sign-in methods continue to work, and the credential remains listed — marked disabled — so the user can see what happened.

Request Body

application/json
ceremony_tokenRequired
string·min 1·max 128
responseRequired
object

The PublicKeyCredential returned by navigator.credentials.get(), serialized as JSON in the form a WebAuthn client library produces.

remember_me
boolean

Whether to remember this device. true (the default when omitted, which preserves earlier client behavior) issues a persistent session cookie with the 7-day idle and 30-day absolute lifetimes. false issues a browser-session cookie that the browser discards when it closes, and the server bounds the session to 48 hours, idle and absolute.

Responses

Start registering a passkey

POST/api/v1/auth/passkeys/register/options

Returns the options to pass to navigator.credentials.create(), together with a single-use ceremony token.

The options require a discoverable credential and user verification, which is what makes the resulting passkey usable for usernameless sign-in. Credentials already registered to the account are excluded, so an authenticator that is already enrolled declines rather than creating a duplicate.

The ceremony is bound to the calling account and can only be completed by it. An account at the ten-passkey limit receives 409.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Responses

Finish registering a passkey

POST/api/v1/auth/passkeys/register/verify

Verifies the authenticator's attestation and stores the credential under the supplied name.

The account is taken from the session, never from the request: a body-supplied user would let a caller enrol a credential onto someone else's account. A ceremony started by a different account is refused.

Registering a passkey does not remove any other sign-in method. It also does not require the account to have one — but the account's last remaining method cannot later be deleted.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
ceremony_tokenRequired
string·min 1·max 128
nameRequired
string·min 1·max 64

The user's own label for the device, shown in their passkey list. Surrounding whitespace is trimmed; control characters are rejected.

responseRequired
object

The PublicKeyCredential returned by navigator.credentials.create(), serialized as JSON in the form a WebAuthn client library produces.

Responses

List the current account's passkeys

GET/api/v1/auth/passkeys

Returns every registered passkey, including any disabled by a clone signal — a disabled credential stays listed because that is how the user finds out something happened to it.

The list is bounded by the ten-passkey registration limit and is not paginated. Public keys and attestation data are deliberately absent: a client has no use for them.

Header Parameters

X-Assign-Realtime-Baseline
string

Upcoming browser-session canonical read custody. The named private scope captures this response and a signed replay cursor in one snapshot. Successful responses include X-Assign-Realtime-Cursor and X-Assign-Realtime-Position. Apply all required retained state before acknowledging the corresponding socket checkpoint. Failed or incomplete baselines return no cursor.

Values
account_security

Responses

Rename a passkey

PATCH/api/v1/auth/passkeys/{passkey_id}

Changes the user's own label for a passkey. The name is a display string only and has no effect on the credential.

Path Parameters

passkey_idRequired
string <uuid>
Example0198ac5e-f9b7-7000-8000-000000000001

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
nameRequired
string·min 1·max 64

The user's own label for the device, shown in their passkey list. Surrounding whitespace is trimmed; control characters are rejected.

Responses

Remove a passkey

DELETE/api/v1/auth/passkeys/{passkey_id}

Removes a passkey from the account. This does not tell the authenticator to forget its copy; the user removes that separately in their platform's own passkey settings.

A passkey belonging to another account is 404, the same answer a malformed identifier receives — a passkey identifier belongs to exactly one account, so the two must not be distinguishable.

Removing the account's last remaining sign-in method is refused with 409 last_sign_in_method. An account with a passkey and no password could otherwise lock itself out in a single request with nothing left to recover with. A password, a linked identity provider, or another usable passkey each satisfy the requirement; a passkey disabled by a clone signal does not, because it is not a way back in.

Path Parameters

passkey_idRequired
string <uuid>
Example0198ac5e-f9b7-7000-8000-000000000001

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Responses

Complete a sign-in with a second factor

POST/api/v1/auth/mfa/verify

Exchanges the challenge from login and a code for a browser session. This is the only place a challenge becomes a session; a challenge on its own reads nothing.

The code may be a TOTP code or one of the account's recovery codes. Recovery codes are matched ignoring spacing and case, and each is accepted exactly once.

A code is refused identically whether it was a wrong TOTP value, an unrecognized recovery code, or one already spent — telling them apart would report which factors the account actually has. A TOTP code is also refused on its second use, so a code observed in transit is not replayable for the rest of its window.

The challenge counts its own attempts and gives up after five, because a six-digit code is reachable by brute force within the challenge lifetime if it never does. An exhausted or expired challenge returns 401 invalid_challenge, and the caller must sign in again.

Request Body

application/json
mfa_tokenRequired
string·min 1·max 128
codeRequired
string <password>·min 1·max 64

Either a six-digit TOTP code or one of the account's recovery codes. Recovery codes are matched after stripping spaces and hyphens and upper-casing, so a code read off paper matches however it was grouped.

remember_me
boolean

Whether to remember this device; use the value chosen at the first sign-in step. true (the default when omitted, which preserves earlier client behavior) issues a persistent session cookie with the 7-day idle and 30-day absolute lifetimes. false issues a browser-session cookie that the browser discards when it closes, and the server bounds the session to 48 hours, idle and absolute.

Responses

Begin enrolling a time-based one-time password factor

POST/api/v1/auth/mfa/totp/setup

Generates a shared secret and returns it once, with the otpauth:// URI a QR code encodes. The secret is never readable again; a client that loses it must start enrolment over.

Setup alone does not enable the factor — sign-in keeps working unchanged until confirmTOTP succeeds, so an abandoned enrolment cannot lock anyone out. Restarting setup replaces any unconfirmed secret, which stops a previously displayed QR code from working.

An account that already has a confirmed factor receives 409: allowing a replacement would let whoever holds a live session swap the second factor out silently.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Responses

Enable the time-based one-time password factor

POST/api/v1/auth/mfa/totp/confirm

Enables the factor once a code from the enrolling authenticator matches, and returns the account's ten recovery codes. Like the secret, the codes are shown exactly once — only their hashes are stored.

The code used here is spent by the confirmation, so it cannot immediately be replayed as a sign-in.

Calling this without a preceding setup returns 409 mfa_not_set_up; calling it when a factor is already confirmed returns 409 mfa_already_enabled.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
codeRequired
string <password>·min 1·max 64

Either a six-digit TOTP code or one of the account's recovery codes. Recovery codes are matched after stripping spaces and hyphens and upper-casing, so a code read off paper matches however it was grouped.

Responses

Remove the time-based one-time password factor

DELETE/api/v1/auth/mfa/totp

Removes the factor and every recovery code that went with it — recovery codes exist only to recover a factor, so leaving them would keep live bearer secrets for something that no longer exists.

Removal requires the current password and a current code (TOTP or recovery). Either alone would let a stolen session or a stolen phone take the protection off by itself.

An account with no confirmed factor receives 409 mfa_not_enabled; an unconfirmed enrolment is not a factor for this purpose.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
current_passwordRequired
string <password>·min 1·max 128
codeRequired
string <password>·min 1·max 64

Either a six-digit TOTP code or one of the account's recovery codes. Recovery codes are matched after stripping spaces and hyphens and upper-casing, so a code read off paper matches however it was grouped.

Responses

Replace the account's recovery codes

POST/api/v1/auth/mfa/recovery-codes/regenerate

Issues a fresh set of ten codes and invalidates every previous one, including any still unused. Like the original set, they are shown exactly once.

The current password is required, because the codes this returns are themselves a way past the second factor. An account with no confirmed factor receives 409 mfa_not_enabled.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
current_passwordRequired
string <password>·min 1·max 128

Responses

Read the current session-bound CSRF token

GET/api/v1/auth/csrf

Opt-in direct browser ingress. Requires an exact configured Origin, the API-host session cookie and its valid session-bound CSRF cookie. Returns no-store JSON for an application on a separate same-site origin. Does not rotate or refresh the session. Browser-managed Origin is never replaced with an arbitrary return URL. Existing same-origin clients continue reading their own CSRF cookie. Unconfigured deployments omit this operation.

Header Parameters

OriginRequired
string <uri>

Browser-managed exact application origin admitted by Core.

Responses

Capture an authentication link in API-host HttpOnly custody

GET/api/v1/auth/continuations/{kind}

Opt-in browser navigation for the configured Astro application. Captures a link token in a purpose-bound encrypted HttpOnly host-only cookie for ten minutes, then redirects to the fixed application route with an opaque continuation marker. Email-change capture additionally requires the current browser session and binds redemption to that account. Existing raw-token and canonical Web/native flows remain valid. A marker submitted to its original POST operation requires the matching cookie and kind; body size is bounded to 65,536 bytes. Successful domain redemption clears the cookie and the original domain token enforces single use. Invitation registration retains custody for the separate acceptance operation. Tokens and continuation cookies must never enter logs or public caches.

Path Parameters

kindRequired
string
Values
passwordemailemail_changeinvitation

Query Parameters

tokenRequired
string·min 1·max 2000

Original link credential; at most 2,000 UTF-8 bytes.

Responses

Log out the current browser session

POST/api/v1/auth/logout

Revokes the current browser session and expires both browser-session cookies. The CSRF header must exactly match the host-only CSRF cookie and the token bound to the authenticated session.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Responses

Start provider sign-in

GET/api/v1/auth/providers/{provider}/authorize

Begins an OAuth/OIDC sign-in attempt with the named provider and redirects the browser to that provider's consent screen. An unknown or disabled provider name reports the same not-found response as any other absent resource.

Path Parameters

providerRequired
string

Identity provider name.

Values
googlegithubapple

Query Parameters

return_to
string·max 4096

Local browser path to resume after provider sign-in. Accepts /oauth/authorize with a query string, token-free /invitations/accept, or /app/ Workspace paths including query and fragment. External URLs and unapproved paths are ignored.

Example/oauth/authorize?client_id=https%3A%2F%2Fchatgpt.com%2Foauth%2Fcodex%2Fclient.json
remember_me
boolean

Pass false to decline "Remember this device": the session issued when the provider callback completes is a browser-session cookie bounded to 48 hours (idle and absolute). Any other value, or omitting it, issues the persistent session.

Responses

Complete a provider ceremony (redirect callback)

GET/api/v1/auth/providers/{provider}/callback

Completes an attempt from a provider that redirects with a query string (Google, GitHub).

The route serves two ceremonies, and which one runs is decided from server-side state, never from the request. A sign-in sets both browser-session cookies and, by default, redirects to the existing /app launch entry. The browser resolves the exact active Workspace ID to its readable path before opening Projects. Accounts without a Workspace continue to Workspace creation; validated explicit continuations retain their destination. It first resolves an exact (provider, provider_subject) identity. If none exists and the provider supplies a verified email matching an existing normalized account address, the callback atomically attaches the new identity and signs in that existing account; an absent or unverified email cannot do so. An identity link started from POST /api/v1/me/identities issues no session and rewrites no cookie — the caller is already signed in — and redirects to the identity settings surface instead. A ceremony is claimed by a single conditional update with its purpose in the predicate, so a link can never be redeemed as a sign-in and a sign-in can never be redeemed as an explicit account-settings link ceremony.

On failure the response still redirects, to the web application's login page with an opaque error indicator, so the content-free authentication boundary is preserved even in a browser navigation.

Path Parameters

providerRequired
string

Identity provider name.

Values
googlegithubapple

Query Parameters

stateRequired
string
codeRequired
string

Responses

Complete a provider ceremony (form_post callback)

POST/api/v1/auth/providers/{provider}/callback

Completes an attempt from a provider that posts form-encoded parameters instead of redirecting with a query string (Apple). Behavior, including the sign-in and identity-link branch, is otherwise identical to the GET callback.

Path Parameters

providerRequired
string

Identity provider name.

Values
googlegithubapple

Request Body

application/x-www-form-urlencoded
stateRequired
string
codeRequired
string

Responses

Authorize a registered first-party developer client

GET/api/v1/dev/oauth/authorize

Completes first-party CLI or IDE authorization from a signed-in system browser. The request must use Authorization Code with PKCE S256, a registered client ID (assign-cli, assign-jetbrains, or assign-vscode), and an exact http loopback callback on 127.0.0.1 or [::1], an ephemeral port, and path /callback. Client secrets, localhost, custom URI schemes, non-loopback hosts, alternate paths, query-bearing callbacks, and PKCE downgrade are rejected. The five-minute code is single-use.

Query Parameters

response_typeRequired
string·const code
client_idRequired
string
Values
assign-cliassign-jetbrainsassign-vscode
redirect_uriRequired
string <uri>
stateRequired
string·min 16·max 2048
code_challengeRequired
string·min 43·max 128
code_challenge_methodRequired
string·const S256

Responses

302Redirect to the exact bound loopback callback with one code and unchanged state.

Exchange a developer-client authorization code or refresh token

POST/api/v1/dev/oauth/token

Exchanges one bound authorization code and PKCE verifier, or rotates the current refresh token. Access tokens expire after 15 minutes. Refresh families expire after 90 days of inactivity and one year absolutely; replay of a consumed refresh token revokes the family. No client secret is accepted.

Request Body

application/x-www-form-urlencoded

Responses

Revoke the calling interactive developer-client credential

POST/api/v1/dev/oauth/revoke

Revokes the complete refresh family. The client removes local credentials even when remote revocation cannot be confirmed.

Responses

Log in from the native password screen

POST/api/v1/mobile/auth/login

First-party native email/password authentication. No browser, callback, cookies, client secret or platform-store registration is involved. Use the fixed client matching the platform and the installation binding. Core preserves password policy, account state, rate limits and MFA. Login returns mfa_required=true with a five-minute, five-attempt challenge when enrolled; no credential is issued before verification. Native MFA challenges cannot be redeemed by browser MFA or another installation. Registration creates an unverified account and sends verification email; verification gates recovery, not access. A verification_delivery_failed response means the account exists; request another email and log in. Passwords and challenges are memory-only; never log or automatically retry.

Request Body

application/json
client_idRequired
string
Values
assign-iosassign-android
platformRequired
string
Values
iosandroid
installation_idRequired
string <password>·min 43·max 128
device_labelRequired
string·min 1·max 64
emailRequired
string <email>·min 3·max 320

Normalized to lowercase and trimmed before storage and comparison.

passwordRequired
string <password>·min 12·max 128

Between 12 and 128 characters. There are deliberately no composition rules: length and non-reuse resist guessing, while character-class rules mostly produce predictable substitutions. Passwords appearing in a known breach corpus are refused.

Responses

Register from the native account screen

POST/api/v1/mobile/auth/register

First-party native email/password authentication. No browser, callback, cookies, client secret or platform-store registration is involved. Use the fixed client matching the platform and the installation binding. Core preserves password policy, account state, rate limits and MFA. Login returns mfa_required=true with a five-minute, five-attempt challenge when enrolled; no credential is issued before verification. Native MFA challenges cannot be redeemed by browser MFA or another installation. Registration creates an unverified account and sends verification email; verification gates recovery, not access. A verification_delivery_failed response means the account exists; request another email and log in. Passwords and challenges are memory-only; never log or automatically retry.

Request Body

application/json
client_idRequired
string
Values
assign-iosassign-android
platformRequired
string
Values
iosandroid
installation_idRequired
string <password>·min 43·max 128
device_labelRequired
string·min 1·max 64
emailRequired
string <email>·min 3·max 320

Normalized to lowercase and trimmed before storage and comparison.

passwordRequired
string <password>·min 12·max 128

Between 12 and 128 characters. There are deliberately no composition rules: length and non-reuse resist guessing, while character-class rules mostly produce predictable substitutions. Passwords appearing in a known breach corpus are refused.

display_name
string·min 1·max 100

Responses

Complete installation-bound native MFA

POST/api/v1/mobile/auth/mfa/verify

First-party native email/password authentication. No browser, callback, cookies, client secret or platform-store registration is involved. Use the fixed client matching the platform and the installation binding. Core preserves password policy, account state, rate limits and MFA. Login returns mfa_required=true with a five-minute, five-attempt challenge when enrolled; no credential is issued before verification. Native MFA challenges cannot be redeemed by browser MFA or another installation. Registration creates an unverified account and sends verification email; verification gates recovery, not access. A verification_delivery_failed response means the account exists; request another email and log in. Passwords and challenges are memory-only; never log or automatically retry.

Request Body

application/json
client_idRequired
string
Values
assign-iosassign-android
platformRequired
string
Values
iosandroid
installation_idRequired
string <password>·min 43·max 128
device_labelRequired
string·min 1·max 64
mfa_tokenRequired
string·min 1·max 512

A single-use, expiring bearer secret delivered by email. Only its hash is stored, so it cannot be recovered from a database disclosure. Treat it as a credential: never log it or place it in a URL you retain.

codeRequired
string <password>·min 1·max 64

Either a six-digit TOTP code or one of the account's recovery codes. Recovery codes are matched after stripping spaces and hyphens and upper-casing, so a code read off paper matches however it was grouped.

Responses

Start or continue native mobile OAuth authorization

GET/api/v1/mobile/oauth/authorize

This is a system-browser-only Authorization Code + PKCE S256 endpoint for a registered Assign Mobile public client. It never accepts a client secret. The browser may use its existing Assign session to complete the request, or it may sign in through the normal browser ceremony before returning here. The API then redirects only to the exact registered callback, which is the production universal/app link https://api.assign.so/mobile/oauth/callback.

The mobile app must not follow this endpoint with an HTTP client, copy browser cookies, or treat the redirect as proof of API access. It receives a short-lived one-time code and exchanges that code at the token endpoint.

Query Parameters

client_idRequired
string·min 1·max 100
redirect_uriRequired
string <uri>·max 2048
stateRequired
string·min 16·max 2048
code_challengeRequired
string·min 43·max 128
code_challenge_methodRequired
string
Values
S256
installation_idRequired
string·min 43·max 128
platformRequired
string
Values
iosandroid
device_labelRequired
string·min 1·max 64
prompt
string
Values
login

Responses

Exchange a native authorization code or refresh token

POST/api/v1/mobile/oauth/token

Exchanges a native authorization code with its PKCE verifier, or the current rotating refresh token, for the next 15-minute opaque access token and refresh token. The request is bound to the registered public client and installation. Responses always carry Cache-Control: no-store; raw credentials must never be logged, cached, or placed in a URL. Reuse of an already-consumed refresh token revokes its entire credential family and requires browser reauthentication.

Request Body

application/json

Responses

Revoke the calling native mobile credential

POST/api/v1/mobile/oauth/revoke

Revokes only the credential represented by the native access token, including its refresh family and push registration. It is idempotent: a token that has already been revoked receives the same credential-free success response. The app clears local credentials and user-sensitive data after this request, whether it succeeds or is already invalid.

Responses

Switch the current session's Workspace

PUT/api/v1/auth/session/workspace

Revokes the current browser session and creates a new one scoped to a different Workspace the caller actively belongs to, rotating the bearer and CSRF secrets. There is no in-place reauthorization of the existing session onto a new scope.

Header Parameters

X-CSRF-TokenRequired
string·min 43·max 43

Session-bound CSRF token. It must exactly match the __Host-assign_csrf cookie sent with the request.

Request Body

application/json
workspace_idRequired
string <uuid>

Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.

Example0198ac5e-f9b7-7000-8000-000000000001

Responses