← Docs

Sign-in methods

Every method below ends the same way: a single-use authorization code, exchanged at POST /api/v1/oauth/token/ for an access token (15-minute lifetime), an ID token, and a rotating refresh token (30-day idle/30-day absolute lifetime for a confidential client, 7-day idle/14-day absolute for a public one — see Sessions). PKCE (code_challenge/code_verifier, S256) is mandatory on every method — there is no non-PKCE path.

Password

POST /api/v1/oauth/authorize/ with email/password. The password itself is verified by authentik, not by this project — this project never stores or logs it. Returns a code directly (201); no redirect hop.

Magic link

POST /api/v1/oauth/magic-link/request/ with just an email. Always responds identically whether or not the account exists — there is no way to distinguish "email sent" from "no such account" from the response, deliberately. The emailed link's token is single-use and exchanged when the browser opens it.

Email OTP

POST /api/v1/oauth/email-otp/request/ sends a 6-digit code (5-minute expiry, 5 wrong attempts before the request is locked and a new one is required), then POST /api/v1/oauth/email-otp/verify/ exchanges the code for the same authorization code every other method produces.

Google

GET /api/v1/oauth/google/start/ redirects to Google's own consent screen; Google redirects back to /api/v1/oauth/google/callback/, which verifies the returned ID token's signature against Google's real JWKS before trusting anything in it. For signing into an existing Organization, whether a brand-new email may self-provision an account this way is governed by that Organization's own allow_self_registration setting (invite_only by default) — it is not on by default.

Passkeys

POST /api/v1/oauth/passkey/authentication/options/ with no email — resolution is credential_id-first, so the browser's own passkey picker is what resolves the account, not a typed-in address. The resulting navigator.credentials.get() assertion is verified at POST /api/v1/oauth/passkey/authentication/verify/, which also runs sign-count clone/replay detection on every login. Adding a passkey to an existing account (never a sign-in action itself) is a separate, authenticated pair — POST /api/v1/passkeys/registration/options/ and .../registration/verify/ — under Profile.

MFA and the device/location step-up gate

An account with TOTP MFA enabled is asked for a second factor on every sign-in, replacing the step-up gate below entirely. An account without it is asked to re-verify (a magic link, email code, or passkey) only from a genuinely new device or a new country — never on every visit. Full detail on Security.

What's not built yet

Apple sign-in is not implemented. Sign-in for any Application other than this dashboard and the OneHux Accounts Portal exists mechanically (any registered Application can use the same endpoints) but has no dedicated onboarding UX built around it yet.