Registration flow

A self-serve user goes through this once, right after signing up.
  1. Sign up with an email and password.
  2. Confirm the email code we send them. This returns a SECURITY_SETUP_REQUIRED challenge, not tokens. If the code didn’t arrive or expired, resend it.
  3. Set up security: register a passkey or turn on 2FA. This is the step that gets tokens.

Login flow

An existing user logs in one of three ways. Passkey sign-in skips challenges entirely. Two calls, with the device’s passkey ceremony in between:
  1. Start a passkey login: you get a session_token and fido2options to pass to the device. No bearer token needed.
  2. Unlock the passkey on the device. Pass fido2options to the platform’s credential API (navigator.credentials.get() on the web, or the native equivalent on iOS and Android). The OS prompts the user for Face ID, Touch ID, or their device PIN, then hands back a signed assertion. Nothing is sent to us during this step.
  3. Finish a passkey login: send the session_token and the assertion. This returns tokens.

Login with password

Password login is one call plus whatever the challenge asks for. The login call itself never returns tokens.
  1. Log in with the email and password. You get back a challenge and, for most challenges, a session_token.
  2. Do what the challenge says. There are three:
  3. If step 2 returned SECURITY_SETUP_REQUIRED or NEW_DEVICE_SECURITY_OPTIONS, set up security: a passkey or 2FA. That’s the call that finally returns tokens.
Two more password endpoints sit outside the login path:

Login with SSO

If your program uses your own identity provider, the user signs in there instead and none of the endpoints above apply. See Single sign-on. Everything after sign-in, including the tokens below, is the same.

Using your tokens

A successful login returns these tokens: Treat all three as credentials. On the web, keep them in an httpOnly cookie or in memory, never localStorage. On mobile, use the Keychain or Keystore. Refresh shortly before expires_in runs out, clear all three on log out, and never write a token to a log.