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
- Your app redirects to
/authorize. It sends itsclient_id,redirect_uri, the scopes, a randomstateandnonce, and a PKCEcode_challenge(the SHA-256 of a secretcode_verifierthat it keeps). - 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.
- Already signed in? If the browser has a Gatekeep session, Gatekeep skips straight to step 5. That’s single sign-on.
- 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.
- Gatekeep redirects back to your
redirect_uriwith a one-timecodeand yourstate. The code is valid for 60 seconds and works once. - Your app exchanges the code at
/token, sending the originalcode_verifier. Gatekeep checks it hashes to the challenge from step 1, then returns tokens. - 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
audis your client ID. Verify it and readsubandemail. - access_token: for calling Gatekeep’s
/userinfo. Itsaudis 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.