Authentication
Browser-session and native OAuth credential lifecycle operations.
Create an account
/api/v1/auth/registerCreates 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/jsonstring <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
string <password>·min 12·max 128Between 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.
string·min 1·max 100Optional. 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.
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Sign in with an email address and password
/api/v1/auth/loginVerifies 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/jsonstring <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
string <password>·min 12·max 128Between 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.
booleanWhether 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Verify an email address
/api/v1/auth/email/verifyRedeems 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Send a new verification message
/api/v1/auth/email/resend-verificationIssues 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Request a password reset
/api/v1/auth/password/forgotIssues 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Reset a password with a token
/api/v1/auth/password/resetRedeems 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/jsonstring·min 1·max 512A 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Change the current user's password
/api/v1/auth/password/changeReplaces 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
Request Body
application/jsonResponses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Start a passkey sign-in
/api/v1/auth/passkeys/login/optionsReturns 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·min 1·max 128The single-use handle for this ceremony. It is a credential — do not log it or place it in a URL.
string <date-time>When the ceremony stops being completable. Roughly five minutes out; after it passes, start a new one.
objectThe WebAuthn options structure, passed to the browser unchanged.
It is deliberately untyped here: it is defined by the WebAuthn
specification rather than by this API, and restating it would create
a second copy to keep in step. Give it to
navigator.credentials.create() or .get() after the usual
base64url decoding a WebAuthn client library performs.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Complete a passkey sign-in
/api/v1/auth/passkeys/login/verifyVerifies 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/jsonobjectThe PublicKeyCredential returned by
navigator.credentials.get(), serialized as JSON in the form a
WebAuthn client library produces.
booleanWhether 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Start registering a passkey
/api/v1/auth/passkeys/register/optionsReturns 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·min 1·max 128The single-use handle for this ceremony. It is a credential — do not log it or place it in a URL.
string <date-time>When the ceremony stops being completable. Roughly five minutes out; after it passes, start a new one.
objectThe WebAuthn options structure, passed to the browser unchanged.
It is deliberately untyped here: it is defined by the WebAuthn
specification rather than by this API, and restating it would create
a second copy to keep in step. Give it to
navigator.credentials.create() or .get() after the usual
base64url decoding a WebAuthn client library performs.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Finish registering a passkey
/api/v1/auth/passkeys/register/verifyVerifies 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
Request Body
application/jsonstring·min 1·max 64The user's own label for the device, shown in their passkey list. Surrounding whitespace is trimmed; control characters are rejected.
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string·min 1·max 64The user's own label for the device, shown in their passkey list. Surrounding whitespace is trimmed; control characters are rejected.
booleanWhether the authenticator reported the credential as syncable. This
never changes for a credential. Together with backup_state it is
what tells a user whether losing the device means losing the
passkey.
booleantrue when the credential was disabled because its signature
counter failed to advance, which indicates a second copy of the
private key. It cannot be used to sign in and cannot be
re-enabled — remove it and register a new one.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
List the current account's passkeys
/api/v1/auth/passkeysReturns 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
stringUpcoming 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.
account_securityResponses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·max 4096Signed scope/User/session-bound replay custody; only when the requested canonical baseline succeeds.
stringDecimal-string snapshot position; only with a successful baseline cursor.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Rename a passkey
/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
Header Parameters
Request Body
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string·min 1·max 64The user's own label for the device, shown in their passkey list. Surrounding whitespace is trimmed; control characters are rejected.
booleanWhether the authenticator reported the credential as syncable. This
never changes for a credential. Together with backup_state it is
what tells a user whether losing the device means losing the
passkey.
booleantrue when the credential was disabled because its signature
counter failed to advance, which indicates a second copy of the
private key. It cannot be used to sign in and cannot be
re-enabled — remove it and register a new one.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Remove a passkey
/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
Header Parameters
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Complete a sign-in with a second factor
/api/v1/auth/mfa/verifyExchanges 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/jsonstring <password>·min 1·max 64Either 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.
booleanWhether 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
string <uuid>Opaque Assign-owned UUIDv7 identifier. Clients must not derive meaning from it.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Begin enrolling a time-based one-time password factor
/api/v1/auth/mfa/totp/setupGenerates 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Enable the time-based one-time password factor
/api/v1/auth/mfa/totp/confirmEnables 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
Request Body
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Remove the time-based one-time password factor
/api/v1/auth/mfa/totpRemoves 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
Request Body
application/jsonResponses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Replace the account's recovery codes
/api/v1/auth/mfa/recovery-codes/regenerateIssues 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
Request Body
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Read the current session-bound CSRF token
/api/v1/auth/csrfOpt-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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Capture an authentication link in API-host HttpOnly custody
/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
Query Parameters
Responses
string <uri>Fixed kind-specific application route with an opaque continuation marker.
stringSecure HttpOnly SameSite=Lax host-only continuation cookie; Max-Age=600.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 1Seconds until the client may retry.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Log out the current browser session
/api/v1/auth/logoutRevokes 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Start provider sign-in
/api/v1/auth/providers/{provider}/authorizeBegins 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
Query Parameters
string·max 4096Local 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.
Responses
string <uri>The provider's authorization URL.
string·const no-storePrevents storage of error responses by clients and intermediaries.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Complete a provider ceremony (redirect callback)
/api/v1/auth/providers/{provider}/callbackCompletes 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
Query Parameters
Responses
string <uri>The web application URL to redirect to.
string·const no-storePrevents storage of error responses by clients and intermediaries.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Complete a provider ceremony (form_post callback)
/api/v1/auth/providers/{provider}/callbackCompletes 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
Request Body
Responses
string <uri>The web application URL to redirect to.
string·const no-storePrevents storage of error responses by clients and intermediaries.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Authorize a registered first-party developer client
/api/v1/dev/oauth/authorizeCompletes 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
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Exchange a developer-client authorization code or refresh token
/api/v1/dev/oauth/tokenExchanges 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.
Revoke the calling interactive developer-client credential
/api/v1/dev/oauth/revokeRevokes the complete refresh family. The client removes local credentials even when remote revocation cannot be confirmed.
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
Log in from the native password screen
/api/v1/mobile/auth/loginFirst-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/jsonstring <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 512A 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.
Register from the native account screen
/api/v1/mobile/auth/registerFirst-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/jsonstring <email>·min 3·max 320Normalized to lowercase and trimmed before storage and comparison.
string <password>·min 12·max 128Between 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
Complete installation-bound native MFA
/api/v1/mobile/auth/mfa/verifyFirst-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/jsonstring·min 1·max 512A 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
Start or continue native mobile OAuth authorization
/api/v1/mobile/oauth/authorizeThis 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
Responses
string <uri>Browser continuation or exact registered callback URI.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Exchange a native authorization code or refresh token
/api/v1/mobile/oauth/tokenExchanges 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/jsonResponses
string·const no-storePrevents storage of error responses by clients and intermediaries.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Revoke the calling native mobile credential
/api/v1/mobile/oauth/revokeRevokes 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
string·const no-storePrevents storage of error responses by clients and intermediaries.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
Switch the current session's Workspace
/api/v1/auth/session/workspaceRevokes 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
Request Body
Responses
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.
integer·min 0Delay in seconds before retrying, when an expected maintenance end is known.
string·const no-storePrevents storage of error responses by clients and intermediaries.
string·min 1·max 200Correlation identifier for the request.
string·const nosniffPrevents user agents from MIME-sniffing the response.