Skip to content

OAuth & PKCE

ArrowLabs Auth implements OAuth 2.1 + OIDC. There are two grant flows, both starting at the authorization endpoint and finishing at the token endpoint.

  • Confidential clients (backends that can keep a client_secret) — Authorization Code.
  • Public clients (SPAs, mobile, anything that can’t hide a secret) — Authorization Code + PKCE. PKCE is required for these.

The SDKs handle both; you just supply a client_secret (confidential) or a PKCE code_verifier (public) at exchange time.

  1. Authorize. Send the user to /api/v1/oauth/authorize with response_type=code, your client_id, redirect_uri, scope (defaults to openid profile email), a state, and — for PKCE — a code_challenge (code_challenge_method=S256). The SDKs build this URL for you.
  2. User authenticates on their org’s sign-in page and is redirected back to your redirect_uri with a ?code=&state=.
  3. Exchange the code at /api/v1/oauth/token for tokens. Confidential clients send the client_secret; public clients send the code_verifier matching the earlier challenge.
  4. You receive an access token, a refresh token, and an id token.
authorize ──▶ user signs in ──▶ redirect (?code) ──▶ token exchange ──▶ access + refresh + id_token

The code_challenge is BASE64URL(SHA256(code_verifier)). Only S256 is accepted (plain is rejected). Generate the verifier/challenge pair, stash the verifier in your session, and supply it at exchange. Both SDKs ship a PKCE helper.

Codes are single-use and expire after 30 seconds. Replaying a used code is treated as a security event — the underlying auth session is revoked.

  • Refresh exchanges a refresh token for a fresh token set. The refresh token rotates on every use; reusing an old one triggers replay detection and revokes the session.
  • Revoke invalidates a refresh token (e.g. on sign-out). Revocation is idempotent — revoking an unknown or already-revoked token still succeeds.