Docs · Getting started

How sign-in works

The redirect, the passkey ceremony and the code exchange, step by step, so you know what your app sees at each point.

Gatekeep uses the OpenID Connect authorization code flow with PKCE. Here’s one sign-in from start to finish.

The flow

  1. Your app redirects to /authorize. It sends its client_id, redirect_uri, the scopes, a random state and nonce, and a PKCE code_challenge (the SHA-256 of a secret code_verifier that it keeps).
  2. Gatekeep checks the request. The client ID must be registered and the redirect URI must match one of its URIs exactly. If not, Gatekeep shows an error page and never redirects, which blocks open-redirect attacks.
  3. Already signed in? If the browser has a Gatekeep session, Gatekeep skips straight to step 5. That’s single sign-on.
  4. The passkey ceremony. The user clicks Sign in with passkey. The browser asks the authenticator (fingerprint, face or PIN) to sign a one-time challenge for your Gatekeep domain. Gatekeep verifies the signature against the public key it stored at enrollment.
  5. Gatekeep redirects back to your redirect_uri with a one-time code and your state. The code is valid for 60 seconds and works once.
  6. Your app exchanges the code at /token, sending the original code_verifier. Gatekeep checks it hashes to the challenge from step 1, then returns tokens.
  7. Your app checks the ID token (your library does this) and signs the user in.

What comes back from /token

{
  "access_token": "eyJhbGciOiJFZERTQSIs…",
  "id_token": "eyJhbGciOiJFZERTQSIs…",
  "refresh_token": "gkr_01JB7Q…",
  "token_type": "Bearer",
  "expires_in": 900
}
  • id_token: who signed in. Its aud is your client ID. Verify it and read sub and email.
  • access_token: for calling Gatekeep’s /userinfo. Its aud is the issuer, not your app. Treat it as opaque.
  • refresh_token: only when you asked for offline_access. See Refresh tokens.

Access and ID tokens last 15 minutes.

Why there’s no client secret

Secrets leak: from mobile apps, single-page apps and repositories. PKCE gives each sign-in its own one-time secret instead, so a stolen code is useless without the verifier only your app holds. Gatekeep requires PKCE with S256 on every request.