Skip to content
FiveCord Docs

Authentication resource

The Authentication resource covers signing up, signing in, recovering an account, and moving a session to a new device. Every route on this page is below /v1/auth.

Authentication and HTTP authentication define credential syntax and the credential namespaces. Changing the credentials of an account that is already signed in is covered by Email and password changes, Multi-factor authentication, and Phone verification.

Most operations need no Authorization credential, because the request has a one-use token, MFA ticket, WebAuthn assertion, or account credential of its own. List authentication sessions, terminate authentication sessions, resend email verification, log out, complete desktop handoff, and create origin handoff are the only operations on this page that read an Authorization credential. Complete desktop handoff reads the header only when its body omits the token field. The first three and create origin handoff require an ordinary user session, and each rejects a bot token and an OAuth2 bearer token with 403 ACCESS_DENIED. All four still admit a session whose account is flagged for suspicious activity.

Every route has a route bucket and is also subject to the global HTTP limit. A route bucket is keyed by the authenticated user when the request has a resolvable credential and by the client IP address otherwise. Bucket or global denial returns 429 RATE_LIMITED.

An invalid JSON shape returns 400 INVALID_FORM_BODY with validation error object entries in errors. An unexpected failure returns 500 INTERNAL_SERVER_ERROR. Every enumerated code on this page is registered in Errors, and every snowflake field is the decimal string form defined by Snowflakes.

When SSO is both enabled and enforced, every local authentication operation returns 403 SSO_REQUIRED. The SSO status route, SSO start and completion, logout, both session routes, every handoff route, and the passkey bridge options, complete, and cancel routes stay available under enforcement. Every other route on this page is a local authentication operation.

A successful sign-in creates one authentication session and issues its token. FiveCord sets no ceiling on live sessions and evicts none when a further session starts, so an account holds one session per sign-in until it revokes them through terminate authentication sessions.

Revoking a session, whether the account revoked it or an administrator terminated it, stops its token authenticating requests. Its main Gateway connection receives Invalid Session with d: false and stays open, unauthenticated. No Gateway Dispatch is emitted for the revocation itself, so a client learns of it from that frame or from the next request that fails to authenticate.

A newly issued session token and the account it belongs to. Password login without a second factor, MFA completion, discoverable WebAuthn authentication, immediate registration, password reset, email reversion, SSO completion, IP authorisation polling, and handoff polling all return these fields.

FieldTypeDescription
token1stringThe newly issued user session token
user_idsnowflakeThe authenticated user ID
userpartial user objectThe public representation of the authenticated account

1 The token is the literal prefix flx_ followed by exactly 36 base62 characters, and this response is the only way to read it

The public single sign-on state. The same object is embedded by the instance discovery document.

FieldTypeDescription
enabled1booleanWhether SSO can be started on this instance
enforced2booleanWhether SSO is required for every user
display_name?stringThe configured provider display name, or null when none is set
redirect_uristringThe default OAuth2 redirect URI used for the provider callback

1 The value is true only when the operator has enabled SSO and the provider has an authorisation URL, a token URL, a client ID, and a JWKS URL or user info URL. Each URL is configured or discovered from the issuer. A provider that lacks any of them reports false

2 The value is true only when enabled is also true, and every local authentication operation then returns 403 SSO_REQUIRED

The parameters for sending the user to the identity provider, bound to one new SSO state.

FieldTypeDescription
authorization_urlstringThe provider authorisation URL with the state, nonce, and PKCE challenge
state1stringThe one-use CSRF state
redirect_uristringThe callback URI bound to this state

1 The first complete SSO request that presents the unexpired state consumes it, whether or not that request then succeeds

A client MUST return the state unchanged and MUST NOT interpret its contents.

SSO completion always issues a session. It extends the authentication token response with the redirect bound to the consumed state.

FieldTypeDescription
tokenstringThe newly issued user session token
user_idsnowflakeThe authenticated user ID
userpartial user objectThe public representation of the authenticated account
redirect_to1stringThe sanitised redirect that was bound to the consumed SSO state

1 The value is the empty string when start SSO received no redirect_to or when the supplied value did not survive sanitisation

Registration pending approval response object

Section titled “Registration pending approval response object”

The ID of a registration that an administrator has yet to approve. Registration returns this object when the account enters approval.

FieldTypeDescription
registration_pending_approvalbooleanAlways true
user_idsnowflakeThe registered account ID awaiting approval

Every authenticated result on this page embeds the public account representation. The partial user object on the Users resource defines it, together with its reply mention preferences.

The ticket and the method list a client needs to finish a login with a second factor. Password login returns this object when the account has one.

FieldTypeDescription
mfabooleanAlways true
ticket1stringThe ticket consumed by a TOTP or WebAuthn MFA completion
allowed_methods2array[string]The methods available to this account, drawn from totp, webauthn, and backup_codes (max 10 items)
totpbooleanWhether the account holds the time-based one-time password authenticator type
webauthn3booleanWhether passkeys are enabled as a second factor
backup_codesbooleanWhether the account holds at least one unconsumed backup code

1 The ticket is retained for five minutes, is destroyed after five failed code attempts, and is consumed by the completion that issues the session

2 The array lists the account’s methods in the fixed order totp, webauthn, then backup_codes, and it omits any value the account cannot use

3 The account holds the WebAuthn authenticator type, which it takes from Set WebAuthn two-factor authentication. A registered credential alone does not set it, except on an account with no password credential, where the passkey is the primary credential and always counts

Both WebAuthn option operations return a PublicKeyCredential request options object that a browser passes straight to its credential request. The WebAuthn authentication options object on the Multi-factor authentication resource defines its fields, together with its WebAuthn credential descriptor and WebAuthn client extension inputs objects.

A challenge issued for MFA completion is also bound to its ticket and account, so it cannot be replayed against discoverable login. The MFA route lists one group of the resolved account’s credentials in allowCredentials, and the discoverable route omits the member, because discovery happens at the authenticator. Passkey domain selection decides the group and rpId on both routes.

A WebAuthn authentication request has the browser credential result as response and the original server challenge as challenge. FiveCord accepts additional WebAuthn fields. The WebAuthn assertion object on the Multi-factor authentication resource defines the fields, together with its WebAuthn assertion response and WebAuthn client extension results objects.

One live session belonging to the authenticated account. The listing is ordered by approximate last activity, newest first.

FieldTypeDescription
id_hash1stringThe base64url SHA-256 digest of the session token
client_info??client info objectThe parsed client metadata recorded when the session was created
masked_ip?stringThe semi-redacted IP address recorded for the session
approx_last_used_at??ISO8601 timestampThe approximate time of the last request that used this session
current2booleanWhether this session supplied the credential for the current request

1 This digest is the only session identifier the API exposes, and it is the exact value accepted by terminate authentication sessions

2 Exactly one entry is true, the session whose token authenticated the request

A client that needs to identify its own session reads the entry whose current is true.

The parsed device metadata recorded for a session or a pending handoff.

FieldTypeDescription
platform??stringThe recorded client platform, resolved from the User-Agent
os??stringThe recorded operating system
browser?1?stringThe recorded browser
devicestringThe device class, either mobile or desktop
location??client location objectThe approximate geolocation derived from the recorded IP address

1 A native or Electron client reports null, as does a session created by an unparseable request. A handoff omits the member entirely

Device metadata is inferred from the client’s request headers. Treat platform as a display label, not a stable application identifier. Location is approximate and can be unavailable. A session then reports null location, while a handoff reports an object with null members.

The approximate geolocation FiveCord derives from the IP address recorded for a session or a handoff.

FieldTypeDescription
city??stringThe approximate city
region??stringThe approximate region
country??stringThe approximate country

The result of checking a password reset token without consuming it.

FieldTypeDescription
valid1booleanWhether the token is valid and unexpired

1 A password reset token expires one hour after it is issued

The state of one IP authorisation ticket, as observed by the device whose sign-in was held.

FieldTypeDescription
completedbooleanWhether the authorisation link has been used and a session has been issued
token?1?stringThe newly issued user session token
user_id?1?snowflakeThe authenticated user ID
user?1?partial user objectThe public representation of the authenticated account

1 The fields are present together only when completed is true, and a still-pending ticket returns completed alone

Username candidates derived from a display name.

FieldTypeDescription
suggestions1array[string]The generated username candidates (max 20 items)

1 The array has at most one candidate. It is empty when the supplied display name derives no permitted username

The code that identifies one pending desktop handoff.

FieldTypeDescription
code1stringThe handoff code to present to the approving device
expires_atISO8601 timestampThe time at which the handoff expires, five minutes after creation
poll_secret?stringThe secret the initiating device presents to read the issued token

1 The code is 12 characters drawn from the alphabet ABCDEFGHJKMNPQRSTUVWXYZ23456789, rendered as two groups of six separated by a hyphen

The device metadata shown to the approving device before it transfers a session.

FieldTypeDescription
statusstringThe state, either pending or expired
client_info?1?client info objectThe initiating device metadata

1 The value is null whenever the status is expired

The state of one desktop handoff as observed by the device that initiated it.

FieldTypeDescription
status1stringThe state, one of pending, expired, or completed
token?2?stringThe newly issued user session token
user_id?2?snowflakeThe authenticated user ID
user?2?partial user objectThe public representation of the authenticated account

1 An unknown code and an expired code both report expired

2 The fields are present together only when the status is completed

The identifier of one stored origin handoff.

FieldTypeDescription
handoff_idstringThe single-use identifier the receiving origin redeems, 32 random bytes as 43 base64url characters

The client state released by one redeemed origin handoff.

FieldTypeDescription
payloadstringThe base64url string stored by create origin handoff, returned unchanged

The official instance is moving its web client from https://web.fluxer.app to https://fluxer.com, and its canary client from https://web.canary.fluxer.app to https://canary.fluxer.com. A passkey works only under the domain it was created for, so a page on a new origin cannot use a passkey created for fluxer.app. The passkey bridge runs that passkey somewhere that can, then hands the result back to the new origin.

The bridge exists only on the official instance and only for requests from the two new origins. It keeps working while the domain migration switch is off, so people already on a new origin can still use their passkeys. Every bridge route on a self-hosted instance returns 403 INVALID_API_ORIGIN.

A ceremony has one of three purposes. login signs in with any passkey the person picks, login_mfa finishes a password login whose second factor is passkeys, and sudo proves sudo mode through start passkey bridge sudo verification. It also has one of two runners. With page, the ceremony runs on the paired legacy origin at /passkey-bridge. With native, the desktop client on the new origin runs it itself.

A ceremony runs in four steps.

  1. The page on the new origin draws a nonce, keeps it, and starts the ceremony with the nonce’s SHA-256 digest.
  2. The runner fetches passkey bridge options, asks the authenticator, and calls complete passkey bridge or cancel passkey bridge.
  3. Completing or cancelling issues a completion code. The page runner gets it in the fragment of return_url and navigates there. The native runner gets it in the response.
  4. The page on the new origin redeems the ceremony once with the nonce and the completion code.

Redemption needs both secrets. Someone who starts a ceremony and sends another person the bridge link holds the nonce, but the completion code reaches the other person’s browser, which holds no nonce.

A ceremony lasts 10 minutes from its start, or 5 minutes for login_mfa, which is the life of an MFA ticket. It is pending until it completes or is cancelled. Only a passkey the account lists for fluxer.app completes a ceremony. A replaced passkey never does.

When the request comes from a new origin and the instance-wide domain migration switch is on, a completed redemption also opens a passkey update for the session it signs in, or for the session that proves sudo mode.

One started passkey bridge ceremony.

FieldTypeDescription
ceremony_idstringThe ceremony identifier, 32 random bytes as 43 base64url characters
bridge_url1?stringThe page that runs the ceremony

1 The paired legacy origin, the path /passkey-bridge, and the ceremony ID as the fragment. Null for the native runner

The WebAuthn request for one pending ceremony.

FieldTypeDescription
optionsWebAuthn authentication options objectThe request options the runner passes to the authenticator

What the runner does after a ceremony completes or is cancelled. Exactly one field is non-null.

FieldTypeDescription
return_url1?stringWhere the page runner goes next, null for the native runner
completion_code2?stringThe code the native runner redeems, null for the page runner

1 Always /passkey-bridge on the new origin, whatever the purpose. The fragment is passkey-bridge= followed by the ceremony ID, a full stop, and the completion code. The page there decides where the code goes next from what the starting tab kept, so the start request cannot choose where the code lands

2 32 random bytes as 43 base64url characters. Each call issues a new one

The result of one redeemed login or login_mfa ceremony.

FieldTypeDescription
statusstringThe ceremony state, either completed or cancelled
token?1stringThe newly issued user session token
user_id?1snowflakeThe authenticated user ID
user?1partial user objectThe public representation of the authenticated account

1 Present together only when the status is completed

GET/v1/auth/sso/statusUnauthenticated

Reads the public single sign-on state of the instance. Authentication is not required. Returns an SSO status object.

The operation stays available while SSO is enforced. It shares the auth:sso:start bucket, which permits 10 requests per 10 seconds.

StatusBodyCondition
200SSO status objectThe public SSO state was read
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling
POST/v1/auth/sso/startUnauthenticated

Starts a single sign-on flow. Authentication is not required. Returns an SSO start object. Send the user to authorization_url unchanged.

FieldTypeDescription
redirect_to?1?stringThe post-authentication redirect to bind to the state
redirect_uri?2?stringThe provider callback URI to use instead of the configured default

1 FiveCord sanitises the value before binding it to the state and discards a value that does not survive, which the SSO completion response reports as the empty string. Sanitisation keeps the trimmed value only when it begins with a single /, is at most 2,048 characters, and contains no carriage return or line feed

2 The accepted values are the instance default reported as redirect_uri by get SSO status and the mobile callback fluxer://auth/sso/callback, and any other value returns the field code INVALID_URL_FORMAT. The accepted value is bound to the state and reused at the token exchange

StatusBodyCondition
200SSO start objectThe state was created
400error responseThe body is malformed or the callback URI is not an accepted value
403error responseSSO is disabled or its resolved configuration is incomplete, returning FEATURE_TEMPORARILY_DISABLED
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The returned state can be completed once and expires after ten minutes. Starting the flow changes no account state and emits no Gateway Dispatch.

10 requests per 10 seconds, on the auth:sso:start bucket.

POST/v1/auth/sso/completeUnauthenticated

Completes a single sign-on flow and signs in or creates the linked account. Authentication is not required. Returns an SSO completion response.

FieldTypeDescription
codestringThe authorisation code returned by the provider (1-4096 characters)
state1stringThe state returned by start SSO (1-4096 characters)

1 The state is consumed on the first call that resolves it, so a repeated request with the same state returns the field code INVALID_OR_EXPIRED_SSO_STATE

FiveCord refuses the adoption only when the account already holds a different provider subject.

The provider exchange and claim resolution can return the field codes INVALID_SSO_AUTHORIZATION_CODE, INVALID_SSO_TOKEN, FAILED_TO_FETCH_SSO_USER_INFO, FAILED_TO_PARSE_SSO_USER_INFO, SSO_PROVIDER_DID_NOT_RETURN_EMAIL, SSO_IDENTITY_MISMATCH, SSO_MISCONFIGURED, INVALID_EMAIL_ADDRESS, EMAIL_DOMAIN_NOT_ALLOWED_FOR_SSO, or SSO_UNABLE_TO_ALLOCATE_DISCRIMINATOR. An unverified provider email uses the field code INVALID_SSO_TOKEN.

Closed registration returns 403 REGISTRATION_CLOSED, an unknown account on an instance with automatic provisioning disabled returns 403 SSO_REQUIRED, an account awaiting approval returns 403 REGISTRATION_PENDING_APPROVAL, and account suspension returns 403 ACCOUNT_SUSPENDED_TEMPORARILY or 403 ACCOUNT_SUSPENDED_PERMANENTLY. A provisioned username or display name containing a blocked substring returns 403 CONTENT_BLOCKED.

A verified provider email that adopts a bot account returns 403 BOT_USER_AUTH_SESSION_CREATION_DENIED, and one that adopts a rejected registration returns 403 REGISTRATION_REJECTED.

StatusBodyCondition
200SSO completion responseSSO completed and a session was issued
400error responseThe body, state, provider exchange, claims, or resolved email is invalid
403error responseSSO, registration policy, a bot account, or account suspension rejects completion
429rate limit responseRoute or global bucket denies the request
500error responseThe identity provider exchange could not be completed
503error responseThe instance is at its in-flight request ceiling

A failed completion requires a fresh SSO flow. A newly created account has a verified email, no local password or authenticator, and default settings. SSO registration accepts no invite and joins no guild.

Approval mode registration instead returns 403 REGISTRATION_PENDING_APPROVAL and creates no session. Otherwise the operation creates one authentication session and clears an expired temporary suspension.

15 requests per 10 seconds, on the auth:sso:complete bucket.

POST/v1/auth/registerUnauthenticated

Creates an ordinary account. Returns an authentication token response when the instance admits the account immediately and a registration pending approval response when it does not. Emits a Guild Member Add Gateway event for each guild the new account joins through an invite or through the instance’s single community guild.

Registration verifies CAPTCHA when CAPTCHA is enabled. It permits 3 attempts per hour for each client IP address and 15 per hour for each client subnet, which is the IPv4 /24 or IPv6 /48 network. A supplied email address permits 3 attempts per 15 minutes of its own. Those allowances are separate from the route bucket, and only a deployment with dev.relax_registration_rate_limits set to true disables them.

FieldTypeDescription
X-Captcha-Token?1stringThe proof issued by the CAPTCHA provider
X-Captcha-Type?2stringThe provider that issued the proof, either hcaptcha or turnstile
Accept-Language?3stringThe language tag that selects the locale stored on the new account

1 A missing proof returns 400 CAPTCHA_REQUIRED and a rejected proof returns 400 INVALID_CAPTCHA, and verification is skipped entirely when CAPTCHA is disabled for the instance

2 Omitting the header selects the instance’s configured provider

3 The parsed locale becomes the account locale and selects the language of the verification email

FieldTypeDescription
email?1stringThe account email address
username?2stringThe account username (1-32 characters, letters, digits, and underscores)
global_name?stringThe display name after normalisation (1-32 characters)
password?3stringThe account password (8-256 characters)
date_of_birth?4stringThe date of birth in exact YYYY-MM-DD form
consent?5booleanWhether the terms of service and privacy policy are accepted (default false)
invite_code??stringThe invite accepted immediately after registration (0-256 characters)
registration_url_code?6?stringThe administrator-issued registration URL code (1-256 characters)
theme?stringThe initial theme preference, one of dark, dark_legacy, coal, light, or system

1 Omitting the email address creates an unclaimed account, which has no recovery path until it is claimed. An address whose domain has no usable DNS records, or whose top-level domain is blocked by account policy, returns the field code INVALID_EMAIL_ADDRESS, and an address already in use returns EMAIL_ALREADY_IN_USE

2 Omitting the username derives one from global_name when that value produces a permitted username, and otherwise allocates a generated username, in both cases with a server-allocated discriminator

3 The password is checked against the public breached-password corpus described under reset a password, and a match returns the field code PASSWORD_IS_TOO_COMMON

4 The field is required when the instance collects date of birth. An absent or blank value, or a value in YYYY-MM-DD shape that is not a real calendar date, returns the field code INVALID_DATE_OF_BIRTH_FORMAT. A value that is not ten characters in YYYY-MM-DD shape fails schema validation with the field code STRING_LENGTH_EXACT or INVALID_FORMAT

5 A false or absent value returns the field code MUST_AGREE_TO_TOS_AND_PRIVACY_POLICY on the official instance and on any instance that publishes a terms or privacy document

6 A code supplied on an instance with administrator registration URLs disabled, and a code that does not resolve, both return 400 REGISTRATION_URL_INVALID. A valid code overrides the closed registration mode and replaces the instance approval mode with its own approval setting

FiveCord resolves the region from the client IP address, and an age below the minimum for that region returns the field code MUST_BE_MINIMUM_AGE. That minimum is 13 years unless account policy sets a different minimum for the region, and the applied minimum appears only in the localised message.

Registration returns 403 REGISTRATION_CLOSED when the instance is closed and no valid registration URL was supplied. A username whose discriminator space is exhausted returns the field code TOO_MANY_USERS_WITH_THIS_USERNAME. A username or display name containing a blocked substring returns 403 CONTENT_BLOCKED.

StatusBodyCondition
200authentication token response | registration pending approval responseRegistration completed or entered the approval state
400error responseThe body, CAPTCHA, account fields, or registration URL code is invalid
403error responseSSO enforcement, registration policy, or content moderation rejects the registration
429rate limit responseA route, global, email, IP, or subnet bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation applies the instance’s registration, email-domain, breached-password, and regional policies before creating the account, and its risk policy can set suspicious activity flags on the created account. It records the accepted terms and privacy policy, authorises the registering client IP address, and sends an email verification message when the instance sends email. An instance that sends no email marks the address verified at creation instead.

Registration accepts the invite_code from the body, or the instance’s configured auto-join invite when the body has none. On an instance with single-community mode enabled, the account also joins the community guild. Each join emits Guild Member Add to the affected guild’s sessions. Registration policy can suppress invite admission.

Approval mode registration creates no guild membership and no authentication session, and the account cannot sign in until an administrator approves it. Every other successful registration creates one session and returns its token.

10 requests per 10 seconds, on the auth:register bucket.

POST/v1/auth/loginUnauthenticated

Validates local email and password credentials. Authentication is not required. Returns an authentication token response when no second factor and no IP approval are outstanding, and an MFA challenge response when the account has a second factor.

Login verifies CAPTCHA when CAPTCHA is enabled. It also permits 10 attempts per client IP address in 30 minutes, keyed by the exact IPv4 address or the IPv6 /64 network, and 5 attempts per email address in 15 minutes. Every admitted attempt consumes both allowances, whether or not the credentials turn out to be correct, and a successful login clears neither.

FieldTypeDescription
X-Captcha-Token?1stringThe proof issued by the CAPTCHA provider
X-Captcha-Type?2stringThe provider that issued the proof, either hcaptcha or turnstile
X-FiveCord-Client-Properties?3stringThe base64-encoded JSON with the reporting client’s os
User-Agent?3stringThe client string recorded on the created session and shown by list authentication sessions

1 A missing proof returns 400 CAPTCHA_REQUIRED and a rejected proof returns 400 INVALID_CAPTCHA, and verification is skipped entirely when CAPTCHA is disabled for the instance

2 Omitting the header selects the instance’s configured provider

3 Both values feed the client info object recorded on the session, and X-FiveCord-Client-Properties is read only for a native FiveCord User-Agent

FieldTypeDescription
emailstringThe account email address
passwordstringThe account password (8-256 characters)
invite_code?1?stringThe invite accepted immediately after a successful login (0-256 characters)

1 The invite is accepted only on a login that completes without a second factor, and a failure to accept it does not fail the login. A login held for IP authorisation discards the invite

A new client IP address on an account that has neither a second factor nor the app store reviewer flag returns 403 IP_AUTHORIZATION_REQUIRED. That error body has ip_authorization_required set to true, the ticket used by the IP authorisation operations, the account email, and resend_available_in set to 30 seconds.

When the instance has disabled new-IP authorisation or sends no email, FiveCord authorises the client IP address silently and the login continues. An account that already has a second factor never enters IP authorisation.

Account policy can return 403 REGISTRATION_PENDING_APPROVAL, 403 REGISTRATION_REJECTED, 403 ACCOUNT_SUSPENDED_TEMPORARILY, or 403 ACCOUNT_SUSPENDED_PERMANENTLY. A bot account returns 403 BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED.

A correct password also clears an expired temporary suspension before any second factor is requested. A live temporary or permanent administrator suspension stays in place, and the login returns its 403.

StatusBodyCondition
200authentication token response | MFA challenge responseThe credentials are accepted
400error responseThe body, CAPTCHA, email, or password is invalid
403error responseAccount policy, SSO enforcement, or IP authorisation prevents the login
409error responseCONFLICT, because the deletion state changed while cancelling a self-scheduled deletion
429rate limit responseA route, global, email, or IP bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

A successful login on an account with a second factor returns an MFA ticket valid for five minutes and issues no session. When IP approval is required, the authorisation ticket remains valid for 15 minutes and the account receives an authorisation message.

A successful login with no outstanding MFA or IP approval creates one authentication session. It accepts the supplied invite first, which emits Guild Member Add to the guild’s sessions.

10 requests per 10 seconds, on the auth:login bucket.

POST/v1/auth/login/mfa/totpUnauthenticated

Consumes an MFA ticket and validates a time-based one-time password or an unconsumed backup code, then creates the session. Authentication is not required. Returns an authentication token response.

MFA verification also permits 10 failed attempts per account in 15 minutes and destroys the ticket after 5 failed attempts.

FieldTypeDescription
code1stringThe authenticator code or an unconsumed backup code
ticketstringThe ticket returned by password login

1 A validated authenticator code is claimed for 30 seconds, so the same code cannot be presented twice. A backup code is consumed permanently on the attempt that accepts it

An expired or unknown ticket returns the field code SESSION_TIMEOUT on ticket. An account with no TOTP enrolment reads code as a backup code, and it returns the field code TOTP_NOT_ENABLED on code only when it holds no unconsumed backup code either. Both an incorrect code and any code presented after the per-account or per-ticket attempt allowance is exhausted return the field code INVALID_CODE on code. A ticket that resolves to a bot account returns 403 BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED.

StatusBodyCondition
200authentication token responseThe ticket and code are accepted
400error responseThe body, ticket, or code is invalid
403error responseSSO enforcement rejects the operation or the ticket resolves to a bot account
404error responseThe ticket resolves to an account that no longer exists
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

Success consumes the ticket, clears the per-account and per-ticket failed-attempt counters, and creates one authentication session. A failure consumes one attempt from each counter. No Gateway Dispatch is emitted.

5 requests per minute, on the shared auth:login:mfa bucket.

POST/v1/auth/login/mfa/webauthn/authentication-optionsUnauthenticated

Resolves the account from an MFA ticket and creates a challenge restricted to that account’s registered credentials. Authentication is not required. Returns a WebAuthn authentication options object.

FieldTypeDescription
ticket1stringThe ticket returned by password login (1-256 characters)

1 The ticket is read but not consumed

A client MUST still complete the returned challenge through complete login with WebAuthn MFA before the ticket expires. An expired or unknown ticket returns the field code SESSION_TIMEOUT on ticket. An account with no credential in the group passkey domain selection picks returns 400 NO_PASSKEYS_REGISTERED.

StatusBodyCondition
200WebAuthn authentication options objectThe ticket resolves to an account with at least one credential
400error responseThe body or ticket is invalid, or the account has no registered credential
403error responseSSO enforcement rejects the operation
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation issues a one-use WebAuthn challenge valid for five minutes and bound to this MFA flow, account, and ticket. It changes no account state. No Gateway Dispatch is emitted.

5 requests per minute, on the shared auth:login:mfa bucket.

POST/v1/auth/login/mfa/webauthnUnauthenticated

Consumes the MFA ticket, verifies the WebAuthn assertion against the challenge, and creates the session. Authentication is not required. Returns an authentication token response.

FieldTypeDescription
responseWebAuthn assertion objectThe browser credential assertion
challenge1stringThe challenge returned by get WebAuthn MFA options
ticketstringThe ticket returned by password login

1 The challenge is consumed before verification and is accepted only when its bound context, account, and ticket all match this request

An expired or unknown ticket returns the field code SESSION_TIMEOUT on ticket. A ticket for an account that does not count passkeys as its second factor returns 400 TWO_FACTOR_REQUIRED, which is what a TOTP account holding registered credentials without Set WebAuthn two-factor authentication receives. A challenge mismatch, an unknown credential, a credential the options did not list, a stored public key that cannot be decoded, a signature counter that the authenticator did not advance, and a failed signature verification all return 401 PASSKEY_AUTHENTICATION_FAILED. A verified assertion whose reported signature counter cannot be read returns 500 INVALID_WEBAUTHN_AUTHENTICATION_COUNTER.

This operation shares the MFA attempt allowances of complete login with TOTP. It permits 10 failed attempts per account in 15 minutes and destroys the ticket after 5 failed attempts. An exhausted allowance returns the field code INVALID_CODE on ticket.

StatusBodyCondition
200authentication token responseThe ticket and assertion are accepted
400error responseThe body or ticket is invalid, or passkeys are not the account’s second factor (TWO_FACTOR_REQUIRED)
401error responseChallenge or assertion verification fails
403error responseSSO enforcement rejects the operation or the ticket resolves to a bot account
404error responseThe ticket resolves to an account that no longer exists
429rate limit responseRoute or global bucket denies the request
500error responseThe verified assertion reported no readable signature counter, or the request could not be completed
503error responseThe instance is at its in-flight request ceiling

Success consumes the challenge and ticket and creates one authentication session. No Gateway Dispatch is emitted.

5 requests per minute, on the shared auth:login:mfa bucket.

POST/v1/auth/webauthn/authentication-optionsUnauthenticated

Creates a challenge for passwordless authentication with a discoverable credential. Authentication is not required. Returns a WebAuthn authentication options object.

The request has no body. The response omits allowCredentials and requests required user verification. Its rpId follows passkey domain selection.

StatusBodyCondition
200WebAuthn authentication options objectA discoverable challenge was created
403error responseSSO enforcement rejects the operation
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation issues a one-use discoverable WebAuthn challenge valid for five minutes and bound to the discoverable context alone. It changes no account state. No Gateway Dispatch is emitted.

20 requests per 10 seconds, on the auth:webauthn:options bucket.

POST/v1/auth/webauthn/authenticateUnauthenticated

Resolves the account from the presented credential ID, verifies the assertion with user verification required, applies account suspension policy, and creates the session. Authentication is not required. Returns an authentication token response.

FieldTypeDescription
responseWebAuthn assertion objectThe browser credential assertion
challenge1stringThe challenge returned by get discoverable WebAuthn options

1 The challenge is consumed before verification and is accepted only when it was issued for the discoverable context, so a challenge issued for MFA or for sudo mode cannot be used here

An unknown credential ID, a challenge mismatch, a credential for another domain than the challenge, a stored public key that cannot be decoded, a signature counter that the authenticator did not advance, and a failed signature verification all return 401 PASSKEY_AUTHENTICATION_FAILED. A verified assertion whose reported signature counter cannot be read returns 500 INVALID_WEBAUTHN_AUTHENTICATION_COUNTER. Account suspension returns 403 ACCOUNT_SUSPENDED_TEMPORARILY or 403 ACCOUNT_SUSPENDED_PERMANENTLY.

A bot account returns 403 BOT_USER_AUTH_SESSION_CREATION_DENIED. An account that has not been admitted returns 403 REGISTRATION_PENDING_APPROVAL or 403 REGISTRATION_REJECTED.

StatusBodyCondition
200authentication token responseThe assertion and account policy are accepted
400error responseThe body is malformed
401error responseChallenge or assertion verification fails
403error responseSSO enforcement, account suspension, a bot account, or an unadmitted registration rejects the login
429rate limit responseRoute or global bucket denies the request
500error responseThe verified assertion reported no readable signature counter, or the request could not be completed
503error responseThe instance is at its in-flight request ceiling

Success consumes the challenge, clears an expired temporary suspension, and creates one authentication session. No Gateway Dispatch is emitted.

10 requests per 10 seconds, on the auth:webauthn:authenticate bucket.

POST/v1/auth/logoutBot

Revokes the session identified by the user session token in the Authorization header. Returns 204 with no body.

The request has no body. The operation requires a credential that resolves to an account, and it admits one flagged for suspicious activity. An absent, malformed, or unknown token returns 401 UNAUTHORIZED. An OAuth2 bearer token returns 403 ACCESS_DENIED. A bot holds no session, so a bot token is accepted and revokes nothing.

StatusBodyCondition
204emptyThe session was revoked, or the credential is a bot token
401error responseThe token is absent, malformed, or names no live session
403error responseThe credential is an OAuth2 bearer token
429rate limit responseRoute or global bucket denies the request
500error responseSession revocation fails unexpectedly
503error responseThe instance is at its in-flight request ceiling

Revoking this session ends its Gateway session as shared behaviour states. No Gateway Dispatch is emitted for the revocation.

20 requests per 10 seconds, on the auth:logout bucket.

POST/v1/auth/verifyUnauthenticated

Consumes an email verification token and marks the account’s current address verified. Authentication is not required. Returns 204 with no body.

FieldTypeDescription
tokenstringThe token delivered by email, exactly 64 characters

An unknown, already consumed, or deleted-account token returns the field code INVALID_OR_EXPIRED_VERIFICATION_TOKEN.

StatusBodyCondition
204emptyThe address was verified
400error responseThe body or token is invalid
403error responseSSO enforcement rejects the operation, or the token resolves to a bot account
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation marks the current address verified, clears its bounced state, and clears every suspicious activity flag that verifying or reverifying an email address satisfies. It emits a User Update Gateway Dispatch to the account’s own sessions.

10 requests per minute, on the auth:verify bucket.

POST/v1/auth/verify/resend

Issues and sends a new email verification token for the authenticated account. Requires a user session token for an ordinary user. Returns 204 with no body.

The request has no body. When the current address is already verified and no reverification suspicious activity flag is set, the operation returns 204 and sends nothing.

StatusBodyCondition
204emptyA message was sent or verification was already complete
401error responseThe user session credential is missing or invalid
403error responseSSO enforcement rejects the operation, or the credential is a bot token or an OAuth2 bearer token
429rate limit responseA route, global, or per-address bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation creates one 64-character verification token bound to the account and its current address, valid for 24 hours, and sends the verification message. Previously issued verification tokens remain valid. No Gateway Dispatch is emitted.

10 requests per minute, on the auth:verify:resend bucket, and the target address permits 3 messages in 15 minutes.

POST/v1/auth/forgotUnauthenticated

Accepts a password recovery request for an email address. Authentication is not required. Returns 204 with no body.

Password recovery verifies CAPTCHA when CAPTCHA is enabled. FiveCord consumes both the client IP address and email address allowances before it validates the address, and exhausting either returns 429.

FieldTypeDescription
X-Captcha-Token?1stringThe proof issued by the CAPTCHA provider
X-Captcha-Type?2stringThe provider that issued the proof, either hcaptcha or turnstile

1 A missing proof returns 400 CAPTCHA_REQUIRED and a rejected proof returns 400 INVALID_CAPTCHA, and verification is skipped entirely when CAPTCHA is disabled for the instance

2 Omitting the header selects the instance’s configured provider

FieldTypeDescription
email1stringThe address that receives the reset link

1 An address whose domain has no usable DNS records returns the field code INVALID_EMAIL_ADDRESS, while an address that passes DNS validation but belongs to no account returns the ordinary success response

StatusBodyCondition
204emptyThe request was accepted regardless of whether the account exists
400error responseThe body, CAPTCHA, or email address is invalid
403error responseSSO enforcement rejects the operation, or the address belongs to a bot account
429rate limit responseA route, global, email, or client IP bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

FiveCord sends one 64-character reset token by email to an address that resolves to an account. The token is bound to that account and its current address, and it is valid for one hour. Nothing else changes. No Gateway Dispatch is emitted.

5 requests per minute, on the auth:forgot bucket, and recovery permits 20 attempts per client IP address and 5 attempts per email address in each 30-minute window.

GET/v1/auth/reset/{token}Unauthenticated

Checks a reset token without consuming it. Authentication is not required. Returns a password reset validity object.

FieldTypeDescription
tokenstringThe password reset token, exactly 64 characters

A well-formed token that is unknown, already consumed, or bound to a deleted account returns the same object with valid set to false.

StatusBodyCondition
200password reset validity objectThe well-formed token was checked
400error responseThe token path parameter fails validation
403error responseSSO enforcement rejects the operation
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

This read does not consume the token or change account state. No Gateway Dispatch is emitted.

20 requests per minute, on the auth:reset:validate bucket.

POST/v1/auth/resetUnauthenticated

Consumes a valid reset token and replaces the account password, then issues a new session or an MFA challenge. Authentication is not required. Returns an authentication token response when the account has no second factor, and an MFA challenge response when it has one.

FiveCord reads the second factor from the account as it stood before the reset. An account that held no password and holds at least one registered WebAuthn credential counts as having one, because the passkey was its primary credential, so it receives an MFA challenge with webauthn in allowed_methods and MUST prove the passkey before the reset yields a session.

FieldTypeDescription
tokenstringThe password reset token, exactly 64 characters
password1stringThe replacement password (8-256 characters)

1 The password is checked against the public breached-password corpus before the token is spent, and a match returns the field code PASSWORD_IS_TOO_COMMON

An unknown or already consumed token, and a token bound to a deleted account, return the field code INVALID_OR_EXPIRED_RESET_TOKEN. A live temporary suspension returns 403 ACCOUNT_SUSPENDED_TEMPORARILY. A permanent suspension returns the field code INVALID_OR_EXPIRED_RESET_TOKEN and never 403 ACCOUNT_SUSPENDED_PERMANENTLY. A bot account returns 403 BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED.

Passwords are checked against a breached-password corpus, as they are during registration and email reversion.

StatusBodyCondition
200authentication token response | MFA challenge responseThe password was replaced
400error responseThe body, token, or replacement password is invalid
403error responseSSO enforcement, a bot account, or a live temporary suspension rejects the mutation
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation replaces the password, records the change time, clears an expired temporary suspension, terminates every authentication session on the account, and consumes the presented reset token. Every terminated session loses its Gateway session as shared behaviour states. Other outstanding reset tokens are not invalidated, so a second recovery link issued earlier still works.

An account with no second factor then receives one new session and its token. An account with a second factor receives a five-minute MFA ticket instead, and the MFA completion creates the session. An account that had no password and holds a registered WebAuthn credential is one of those, and its ticket is completed through complete login with WebAuthn MFA, or through complete login with TOTP when allowed_methods lists backup_codes.

10 requests per minute, on the auth:reset bucket.

POST/v1/auth/email-revertUnauthenticated

Consumes the token delivered to the previous email address, restores that address, replaces the password, terminates every authentication session, and clears every second factor. The requesting IP address becomes the only authorised IP address. Returns an authentication token response. Emits a User Update Gateway event.

The token is valid for 24 hours after the address change that issued it.

FieldTypeDescription
tokenstringThe email reversion token, exactly 64 characters
password1stringThe replacement password (8-256 characters)

1 The value becomes the account’s new password, and FiveCord checks it against the public breached-password corpus, returning the field code PASSWORD_IS_TOO_COMMON on a match

An unknown or already consumed token, and a token bound to an account that no longer exists, return the field code INVALID_OR_EXPIRED_REVERT_TOKEN. Account suspension returns 403 ACCOUNT_SUSPENDED_TEMPORARILY or 403 ACCOUNT_SUSPENDED_PERMANENTLY, and a bot account returns 403 BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED.

FiveCord checks the replacement password against the same breached-password corpus described under reset a password before it spends the token.

StatusBodyCondition
200authentication token responseThe address and credential recovery completed
400error responseThe body, token, or replacement password is invalid
403error responseSSO enforcement, a bot account, or account suspension rejects the mutation
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The previous email address becomes verified and the replacement password becomes the account password. All other sessions, second factors and authorised IP addresses are removed. Only the requesting IP address remains authorised.

The account receives User Update. Existing Gateway sessions end as described under shared behaviour, and the response returns one new authentication session.

10 requests per minute, on the auth:email_revert bucket.

GET/v1/auth/sessions

Lists every live authentication session belonging to the authenticated account, newest activity first. Requires a user session token for an ordinary user. Returns an array of authentication session objects.

The request has no body and takes no parameters.

StatusBodyCondition
200array[authentication session object]The live sessions were read
401error responseThe user session credential is missing or invalid
403error responseThe credential is a bot token or an OAuth2 bearer token
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

This read does not change session state. No Gateway Dispatch is emitted.

40 requests per 10 seconds, on the auth:sessions bucket.

POST/v1/auth/sessions/logoutMFA

Deletes the named authentication sessions. Requires a user session token for an ordinary user, and sudo mode. Returns 204 with no body.

The caller MUST send a valid sudo token in the X-FiveCord-Sudo-Mode-JWT header, or supply a password or MFA proof in the body.

FieldTypeDescription
session_id_hashes1array[string]The session digests to delete (max 100 entries)
password?2stringThe password proof for an account holding no TOTP secret and no registered WebAuthn credential (8-256 characters)
mfa_method?3stringThe proof method, either totp or webauthn
mfa_code?stringThe authenticator code or an unconsumed backup code when the method is totp (1-32 characters)
webauthn_response?WebAuthn assertion objectThe assertion when the method is webauthn
webauthn_challenge?stringThe challenge bound to the sudo mode assertion

1 Each value is the base64url id_hash from list authentication sessions. FiveCord ignores an unknown identifier, and an empty array deletes nothing and still returns 204

2 The password is accepted only while the account holds neither a TOTP secret nor a registered WebAuthn credential, and a value that does not match returns the field code INVALID_PASSWORD

3 The MFA proof is accepted only while the account holds a TOTP secret or a registered WebAuthn credential, which a passkey satisfies whether or not passkeys are enabled as a second factor. Any failure returns the field code INVALID_MFA_CODE on mfa_code, and a successful proof issues a fresh sudo token

A totp method reads mfa_code as an authenticator code and accepts an unconsumed backup code in its place, and it reads the value as a backup code alone while the account holds no TOTP secret. A webauthn method reads webauthn_response and webauthn_challenge together, and it accepts only a challenge that was issued for the sudo context.

Missing or unusable proof returns 403 SUDO_MODE_REQUIRED, whose error body has top-level has_mfa and methods members, and methods reports whether totp, webauthn, and backup_codes are available.

StatusBodyCondition
204emptyEvery named session was absent or deleted
400error responseThe body or the supplied proof is invalid
401error responseThe user session credential is missing or invalid
403error responseThe credential is a bot token or an OAuth2 bearer token, or sudo mode is required
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

Each named session is deleted and loses its Gateway session as shared behaviour states. A fresh MFA proof issues a new sudo token, while an accepted incoming token is echoed unchanged. FiveCord sets whichever token results in the X-FiveCord-Sudo-Mode-JWT response header. A password proof, which only an account holding neither a TOTP secret nor a registered WebAuthn credential can give, issues no token, so the header is not set unless the request already had one. No Gateway Dispatch is emitted.

20 requests per 10 seconds, on the auth:sessions:logout bucket.

POST/v1/auth/authorize-ipUnauthenticated

Consumes the authorisation token delivered by email, authorises the pending client IP address, and completes the waiting login. Authentication is not required. Returns 204 with no body.

FieldTypeDescription
tokenstringThe authorisation token delivered by email

An unknown, expired, already consumed, or account-mismatched token returns the field code INVALID_OR_EXPIRED_AUTHORIZATION_TOKEN. A token that resolves to an account that no longer exists returns 404 UNKNOWN_USER, and one that resolves to a bot account returns 403 BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED. Session creation also rejects an account that has not been admitted or is suspended, with the codes listed under log in with a password.

StatusBodyCondition
204emptyThe IP address was authorised and the new session token is readable through poll IP authorisation
400error responseThe body or authorisation token is invalid
403error responseSSO enforcement rejects the operation or the token resolves to a bot account
404error responseThe token resolves to an account that no longer exists
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation adds the pending client IP address to the account’s authorised set and creates one authentication session. That session takes the IP address, user agent, and reported operating system captured when the login was attempted. It consumes the authorisation token and the ticket for the pending login.

The session token is then published against the ticket and remains readable by poll IP authorisation for 60 seconds. The caller of this operation receives 204 and no token of its own. No Gateway Dispatch is emitted.

5 requests per minute, on the auth:authorize_ip bucket.

POST/v1/auth/ip-authorization/resendUnauthenticated

Sends the authorisation message for an outstanding IP authorisation ticket again. Authentication is not required. Returns 204 with no body.

FieldTypeDescription
ticket1stringThe ticket returned by the IP_AUTHORIZATION_REQUIRED login error

1 The resend reuses the authorisation token already bound to the ticket, so a message delivered by an earlier send remains valid

An unknown or expired ticket returns the field code INVALID_OR_EXPIRED_AUTHORIZATION_TICKET. A resend less than 30 seconds after the ticket was issued returns 429 IP_AUTHORIZATION_RESEND_COOLDOWN with a Retry-After header and a top-level resend_available_in in seconds. A second resend returns 400 IP_AUTHORIZATION_RESEND_LIMIT_EXCEEDED.

StatusBodyCondition
204emptyThe message was sent again
400error responseThe body or ticket is invalid, or the ticket’s single resend is already used
403error responseSSO enforcement rejects the operation
429rate limit responseA route or global bucket denies the request, or the resend delay has not elapsed
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

FiveCord sends the authorisation message to the address associated with the login attempt and marks the ticket’s single resend used whether or not delivery succeeds. No account state changes. No Gateway Dispatch is emitted.

5 requests per minute, on the auth:ip_authorization_resend bucket, and each ticket permits exactly one resend, no earlier than 30 seconds after the ticket was issued.

GET/v1/auth/ip-authorization/pollUnauthenticated

Reads the login result associated with an IP authorisation ticket. Authentication is not required. Returns an IP authorisation poll object.

FieldTypeDescription
ticketstringThe ticket returned by the IP_AUTHORIZATION_REQUIRED login error

An unknown or expired ticket returns the field code INVALID_OR_EXPIRED_AUTHORIZATION_TICKET, which is also the outcome once the 60-second result retention has elapsed.

StatusBodyCondition
200IP authorisation poll objectThe ticket was read
400error responseThe query is malformed or the ticket is unknown or expired
403error responseSSO enforcement rejects the operation
404error responseThe completed result names an account that no longer exists, returning UNKNOWN_USER
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

60 requests per minute, on the auth:ip_authorization_poll bucket.

POST/v1/auth/username-suggestionsUnauthenticated

Derives username candidates from a display name. Authentication is not required. Returns a username suggestions object.

The route shares the auth:register bucket, which permits 10 requests per 10 seconds.

FieldTypeDescription
global_namestringThe display name after normalisation (1-32 characters)
StatusBodyCondition
200username suggestions objectCandidates were generated
400error responseThe body or display name is invalid
403error responseSSO enforcement rejects the operation
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

This read reserves no username and changes no account state. No Gateway Dispatch is emitted.

POST/v1/auth/handoff/initiateUnauthenticated

Creates a pending handoff and returns the code the initiating device shows to an already signed-in device. Authentication is not required. Returns a handoff initiation object.

The request has no body. FiveCord derives the device metadata shown to the approving device from the request itself.

FieldTypeDescription
User-Agent?stringThe client string presented to the approving device and recorded on the session the handoff creates
X-FiveCord-Client-Properties?stringThe base64-encoded JSON with the reporting client’s os, read only for a native FiveCord User-Agent
StatusBodyCondition
200handoff initiation objectA handoff request was created
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The handoff remains pending for five minutes and records the initiating device’s client IP address, user agent, and reported operating system. Initiation creates no session. No Gateway Dispatch is emitted.

10 requests per minute, on the auth:handoff:initiate bucket.

GET/v1/auth/handoff/{code}/infoUnauthenticated

Describes the device that initiated a pending handoff so that the approving device can show it before approving, and marks the code approvable. Authentication is not required. Returns a handoff information object.

FiveCord counts failed code attempts against the client IP address and blocks it after 5 failures in 15 minutes. A pending result records no failure, while an unknown or expired code records one.

FieldTypeDescription
code1stringThe handoff code

1 FiveCord normalises the value by removing hyphens and whitespace and upper-casing the rest, and the normalised result is exactly 12 characters from the handoff alphabet

Anyone who can reach the API and knows the code can mark it inspected. Declining the request in a client discards only what that client is showing, and the inspected state remains until the handoff is completed or the code expires.

A code that is not exactly 12 characters from the handoff alphabet after hyphens and whitespace are removed returns 400 INVALID_HANDOFF_CODE. Both a code whose three lookups are already spent and a request from a client IP address that has exhausted its failed-attempt allowance return the same error code. An unknown or expired code returns 200 with the expired status and records one failed attempt.

StatusBodyCondition
200handoff information objectThe pending or expired state was read
400error responseThe code is malformed, its lookup budget is spent, or the client IP attempt allowance is exhausted
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

A successful lookup consumes one of the code’s three lookups and permits complete desktop handoff. An expired result counts as a failed attempt. No account state changes or Gateway Dispatch occur.

10 requests per minute, on the auth:handoff:info bucket, and each code permits at most three successful lookups in total, counted on the code itself.

POST/v1/auth/handoff/complete

Approves a pending handoff by issuing a new session to the initiating device on the authority of a live one. Requires the approving device’s own user session token. Returns 204 with no body.

FiveCord reads that token from the Authorization header, or from the body token field when the body supplies one.

FieldTypeDescription
code1stringThe handoff code shown by the initiating device
token?2stringThe approving device’s own user session token
user_id3snowflakeThe account the approving session belongs to

1 The code uses the same normalisation contract as get desktop handoff information, and only a code that operation has already inspected is accepted

2 The body token takes precedence over the Authorization header, and a request that supplies neither returns 401 UNAUTHORIZED

3 A supplied token that resolves to a different account returns SESSION_TOKEN_MISMATCH

A token that resolves to no live session returns 401 INVALID_TOKEN. A malformed, unknown, completed or uninspected code returns 400 INVALID_HANDOFF_CODE, as does an exhausted failed-attempt allowance. An expired code returns INVALID_HANDOFF_CODE or HANDOFF_CODE_EXPIRED. Start a new handoff in either case.

Session creation can also return 403 BOT_USER_AUTH_SESSION_CREATION_DENIED for a bot account, and 403 REGISTRATION_PENDING_APPROVAL or 403 REGISTRATION_REJECTED for an account that has not been admitted. A suspended account returns the suspension codes listed under log in with a password.

StatusBodyCondition
204emptyThe handoff was completed
400error responseThe body, code, expiry state, or session ownership is invalid
401error responseThe approving credential is missing, invalid, or revoked
403error responseThe approving session belongs to a bot or to an account awaiting approval or rejected
404error responseThe approving session resolves to an account that no longer exists
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

Completion creates one new authentication session for the initiating device and publishes its token against the code. The token stays readable through get desktop handoff status for whatever remains of the handoff’s five minutes. Completion also discards the pending handoff, so the code cannot be completed a second time and a later get desktop handoff information reports expired.

The approving session remains valid. The new session takes the initiating device’s client IP address, user agent, and reported operating system from the handoff record. No Gateway Dispatch is emitted.

10 requests per minute, on the auth:handoff:complete bucket, and a client IP address is blocked after 5 failed code attempts in 15 minutes.

GET/v1/auth/handoff/{code}/statusUnauthenticated

Reports the state of a handoff to the device that initiated it. Authentication is not required. Returns a handoff status object.

FieldTypeDescription
codestringThe handoff code, using the same normalisation contract as get desktop handoff information

The code is the only credential this route checks. The initiating device MUST poll for the completion itself.

StatusBodyCondition
200handoff status objectThe state was read, or an unknown code was reported as expired
400error responseThe code is malformed, returning INVALID_HANDOFF_CODE
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

A poll leaves the handoff unchanged. A poll against a completed handoff records a failed attempt for the polling IP address, because this route presents no poll_secret. No account state changes and no Gateway Dispatch is emitted.

60 requests per minute, on the auth:handoff:status bucket.

Get desktop handoff status with the poll secret

Section titled “Get desktop handoff status with the poll secret”
POST/v1/auth/handoff/{code}/statusUnauthenticated

Reports the state of a handoff and delivers the new session token once, to a caller that presents the poll secret issued at initiation. Authentication is not required. Returns a handoff status object.

FieldTypeDescription
codestringThe handoff code, using the same normalisation contract as get desktop handoff information
FieldTypeDescription
poll_secretstringThe secret returned by initiate desktop handoff

A secret that does not match reports pending and records a failed attempt for the polling IP address. The route reports no distinct error for a wrong secret, so a caller cannot tell a wrong secret from a handoff the approving device has not finished.

StatusBodyCondition
200handoff status objectThe state was read, or an unknown code was reported as expired
400error responseThe code is malformed, returning INVALID_HANDOFF_CODE
404error responseThe completed handoff names an account that no longer exists, returning UNKNOWN_USER
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

Retrieving the token completes the handoff. Other polls leave it unchanged. No Gateway Dispatch is emitted.

60 requests per minute, on the auth:handoff:status bucket.

DELETE/v1/auth/handoff/{code}Unauthenticated

Discards a handoff and everything stored against its code. Authentication is not required. Returns 204 with no body.

FieldTypeDescription
codestringThe handoff code, using the same normalisation contract as get desktop handoff information
FieldTypeDescription
poll_secretstringThe secret returned by initiate desktop handoff

An unknown or already expired code has no stored secret, so it returns 400 INVALID_HANDOFF_CODE.

StatusBodyCondition
204emptyThe handoff was discarded
400error responseThe code is malformed, or the secret does not match, returning INVALID_HANDOFF_CODE
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

Cancelling prevents any further token retrieval but does not revoke a session already created by completion. No Gateway Dispatch is emitted.

10 requests per minute, on the auth:handoff:cancel bucket.

POST/v1/auth/origin-handoff

Stores encrypted client state so that another web origin of the same instance can take it over once. The official web client uses it to move a signed-in browser from its legacy origin to a new one. Requires a user session token. Returns an origin handoff object.

The sending origin encrypts the state and keeps the key. FiveCord never receives the key and never reads the payload. The receiving origin holds a nonce, and the sender passes only its digest here.

FieldTypeDescription
nonce_hashstringThe SHA-256 digest of the receiving origin’s nonce, as 64 lowercase hex characters
payloadstringThe encrypted client state as base64url, 1 to 8388608 characters

A bot token and an OAuth2 bearer token both return 403 ACCESS_DENIED. A session whose account is flagged for suspicious activity is admitted.

StatusBodyCondition
200origin handoff objectThe state was stored
400error responseThe body is invalid, returning INVALID_FORM_BODY
400error responseThe body is larger than 8 MiB plus 1 KiB and the request returns FILE_SIZE_TOO_LARGE
401error responseThe user session credential is missing or invalid
403error responseThe credential is a bot token or an OAuth2 bearer token
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

FiveCord keeps the payload, the nonce digest, and the account ID for two minutes under a key derived from the identifier. Creating a handoff creates no session and changes no account state. No Gateway Dispatch is emitted.

3 requests per 10 minutes, on the auth:origin_handoff:create bucket.

POST/v1/auth/origin-handoff/redeemUnauthenticated

Releases the client state stored by create origin handoff and deletes it in the same step. Authentication is not required. Returns an origin handoff payload object.

FieldTypeDescription
handoff_idstringThe identifier returned by create origin handoff, 43 base64url characters
noncestringThe nonce whose digest the sender supplied, as base64url, 16 to 256 characters

An unknown, expired, or already redeemed identifier returns 404 UNKNOWN_ORIGIN_HANDOFF. A nonce whose SHA-256 digest does not match returns 400 INVALID_ORIGIN_HANDOFF_NONCE.

On an instance that is not self-hosted, the request MUST send an Origin header naming one of the instance’s web app origins. Any other Origin, or none, returns 403 INVALID_API_ORIGIN. A self-hosted instance skips this check.

StatusBodyCondition
200origin handoff payload objectThe state was released and deleted
400error responseThe body is invalid, or the nonce does not match
403error responseThe Origin is not a web app origin of the instance, returning INVALID_API_ORIGIN
404error responseNo stored handoff has this identifier, returning UNKNOWN_ORIGIN_HANDOFF
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

A redemption that finds the handoff deletes it, whether or not the nonce matches. Redemption creates no session. The payload is all the receiving origin gets. No Gateway Dispatch is emitted.

10 requests per minute, on the auth:origin_handoff:redeem bucket.

POST/v1/auth/passkey-bridgeUnauthenticated

Starts a login or login_mfa passkey bridge ceremony. Authentication is not required. Returns a passkey bridge start object.

FieldTypeDescription
purposestringThe purpose, either login or login_mfa
runnerstringWhere the ceremony runs, either page or native
ticket?1stringThe ticket returned by password login (1-256 characters)
nonce_hashstringThe SHA-256 digest of the nonce the new origin keeps, as 64 lowercase hex characters

1 Required for login_mfa and refused for login. The ticket is read but not consumed

The request MUST send an Origin header of https://fluxer.com or https://canary.fluxer.com. Any other Origin, none, or a self-hosted instance returns 403 INVALID_API_ORIGIN.

For login_mfa, an expired or unknown ticket returns the field code SESSION_TIMEOUT on ticket. A ticket for an account that does not count passkeys as its second factor returns 400 TWO_FACTOR_REQUIRED, and one for an account with no passkey listed for fluxer.app returns 400 NO_PASSKEYS_REGISTERED. A ticket that resolves to a bot account returns 403 BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED.

StatusBodyCondition
200passkey bridge start objectThe ceremony was started
400error responseThe body or ticket is invalid, passkeys are not the second factor, or the account has no fluxer.app passkey
403error responseSSO enforcement rejects the operation, the Origin is refused, or the ticket resolves to a bot account
404error responseThe ticket resolves to an account that no longer exists
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

FiveCord stores the ceremony for 10 minutes, or 5 minutes for login_mfa, under a key derived from its identifier. It changes no account state. No Gateway Dispatch is emitted.

10 requests per minute, on the auth:passkey_bridge:start bucket.

POST/v1/auth/passkey-bridge/{ceremony_id}/optionsUnauthenticated

Issues the WebAuthn request for a pending passkey bridge ceremony. Authentication is not required. Returns a passkey bridge options object.

FieldTypeDescription
ceremony_idstringThe identifier from the start response, 43 base64url characters

The request has no body. Its Origin MUST be the origin that runs the ceremony, which is the paired legacy origin for page and the new origin for native. Any other Origin returns 403 INVALID_API_ORIGIN. An unknown, expired, completed, or cancelled ceremony returns 404 UNKNOWN_PASSKEY_BRIDGE, as does a request that arrives while another request holds the same ceremony.

A login ceremony gets options with no allowCredentials and required user verification. A login_mfa or sudo ceremony gets the account’s passkeys for fluxer.app in allowCredentials and discouraged user verification, and an account left with none returns 400 NO_PASSKEYS_REGISTERED. rpId is always fluxer.app.

StatusBodyCondition
200passkey bridge options objectA challenge was issued
400error responseThe ceremony ID is malformed, or the account has no passkey for fluxer.app
403error responseThe Origin is refused, returning INVALID_API_ORIGIN
404error responseThe ceremony is not pending, returning UNKNOWN_PASSKEY_BRIDGE
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The operation issues a one-use challenge valid for five minutes and bound to the bridge, so no other WebAuthn route accepts it. It revokes the challenge the ceremony held before, so only the latest options can complete it. No Gateway Dispatch is emitted.

20 requests per minute, on the auth:passkey_bridge:ceremony bucket, shared with complete and cancel.

POST/v1/auth/passkey-bridge/{ceremony_id}/completeUnauthenticated

Verifies the assertion for a pending passkey bridge ceremony and marks it completed. Authentication is not required. Returns a passkey bridge finish object.

FieldTypeDescription
ceremony_idstringThe identifier from the start response, 43 base64url characters
FieldTypeDescription
responseWebAuthn assertion objectThe browser credential assertion

The Origin rule and the 404 cases are those of get passkey bridge options. FiveCord verifies the assertion against the latest challenge and accepts only the ceremony origin in its client data.

A ceremony with no options issued yet, a credential that is unknown, belongs to another account, is replaced, or is not for fluxer.app, and a failed verification all return 401 PASSKEY_AUTHENTICATION_FAILED. A verified assertion whose reported signature counter cannot be read returns 500 INVALID_WEBAUTHN_AUTHENTICATION_COUNTER.

A login_mfa ceremony whose ticket has expired returns the field code SESSION_TIMEOUT on ticket. It draws one attempt from the login MFA allowances, and an exhausted allowance returns the field code INVALID_CODE on ticket. A sudo ceremony draws one attempt from the sudo allowance, and an exhausted allowance returns the field code INVALID_MFA_CODE on mfa_code.

StatusBodyCondition
200passkey bridge finish objectThe assertion was accepted
400error responseThe body, ceremony ID, or ticket is invalid, or an MFA allowance is exhausted
401error responseChallenge or assertion verification fails
403error responseThe Origin is refused, or the ticket resolves to a bot account
404error responseThe ceremony is not pending, returning UNKNOWN_PASSKEY_BRIDGE
429rate limit responseRoute or global bucket denies the request
500error responseThe verified assertion reported no readable signature counter, or the request could not be completed
503error responseThe instance is at its in-flight request ceiling

Success consumes the challenge, advances the credential’s signature counter, sets its last use, and stores the completion code’s digest with the ceremony. It creates no session and consumes no MFA ticket. No Gateway Dispatch is emitted.

20 requests per minute, on the shared auth:passkey_bridge:ceremony bucket.

POST/v1/auth/passkey-bridge/{ceremony_id}/cancelUnauthenticated

Marks a passkey bridge ceremony cancelled so the new origin can stop waiting. Authentication is not required. Returns a passkey bridge finish object.

FieldTypeDescription
ceremony_idstringThe identifier from the start response, 43 base64url characters

The request has no body, and the Origin rule is that of get passkey bridge options. Cancelling a cancelled ceremony succeeds again with a new completion code. A completed, unknown, or expired ceremony returns 404 UNKNOWN_PASSKEY_BRIDGE.

StatusBodyCondition
200passkey bridge finish objectThe ceremony is cancelled
400error responseThe ceremony ID is malformed
403error responseThe Origin is refused, returning INVALID_API_ORIGIN
404error responseThe ceremony is completed or does not exist, returning UNKNOWN_PASSKEY_BRIDGE
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

The ceremony stores the digest of the new completion code. No account state changes and no Gateway Dispatch is emitted.

20 requests per minute, on the shared auth:passkey_bridge:ceremony bucket.

POST/v1/auth/passkey-bridge/{ceremony_id}/redeemUnauthenticated

Redeems a finished login or login_mfa passkey bridge ceremony once. Authentication is not required. Returns a passkey bridge sign-in redemption object.

FieldTypeDescription
ceremony_idstringThe identifier from the start response, 43 base64url characters
FieldTypeDescription
noncestringThe nonce whose digest started the ceremony, as base64url, 16 to 256 characters
completion_codestringThe completion code from the return fragment or the finish response, 43 base64url characters

The Origin MUST be the new origin that started the ceremony, or the request returns 403 INVALID_API_ORIGIN. A pending ceremony and a sudo ceremony return 404 UNKNOWN_PASSKEY_BRIDGE and stay in place, as does an unknown or expired identifier. A wrong nonce or completion code returns 400 INVALID_PASSKEY_BRIDGE_NONCE.

A cancelled ceremony returns cancelled. A completed login ceremony creates a session under the policy of authenticate with WebAuthn, so a suspended, bot, or unadmitted account gets the same 403 codes. A completed login_mfa ceremony needs its ticket once more, and an expired one returns the field code SESSION_TIMEOUT on ticket. An account that no longer counts passkeys as its second factor returns 400 TWO_FACTOR_REQUIRED.

StatusBodyCondition
200passkey bridge sign-in redemption objectThe ceremony was redeemed
400error responseThe body, ceremony ID, or ticket is invalid, a secret does not match, or passkeys are no longer the second factor
403error responseSSO enforcement, the Origin, account suspension, a bot account, or an unadmitted registration rejects the request
404error responseNo redeemable sign-in ceremony has this identifier, returning UNKNOWN_PASSKEY_BRIDGE
429rate limit responseRoute or global bucket denies the request
500error responseUnexpected internal failure occurs
503error responseThe instance is at its in-flight request ceiling

A redemption that gets past the secret check deletes the ceremony, whatever happens next. A completed ceremony creates one authentication session, and for login_mfa it also consumes the ticket and clears the login MFA allowances. When the request comes from a new origin and the domain migration switch is on, FiveCord opens a passkey update for the new session. No Gateway Dispatch is emitted.

60 requests per minute, on the auth:passkey_bridge:redeem bucket.