← Back to all posts

OIDC

OIDC done minimal: code flow, JWKS, and the road to PKCE

11 min

What a small OIDC provider looks like: Discovery, /authorize, one-shot codes, /token with no-store, /userinfo, /jwks — and the hardening list before public clients.

OIDC is large. The slice that matters for a self-hosted SSO IdP serving confidential clients is much smaller, and we ship that slice intentionally.

Endpoints we serve

  • GET /.well-known/openid-configuration — Discovery.
  • GET /authorize — authorization endpoint, response_type=code.
  • POST /token — token endpoint, grant_type=authorization_code.
  • GET /userinfo — UserInfo, Bearer access token.
  • GET /jwks — JWKS for IdP-issued JWTs (RS256).

Strong defaults already in place

  • redirect_uri exact-match against per-client allowlist.
  • One-shot authorization codes with TTL and timing-safe comparison.
  • no-store on the token endpoint to keep tokens out of intermediaries.
  • RS256 signing only; alg never sourced from the request.

The road to PKCE

Today the flow assumes confidential clients. To serve public, native and SPA clients safely, the next steps are:

  • Accept and store code_challenge + code_challenge_method at /authorize.
  • Verify code_verifier at /token with constant-time comparison.
  • Advertise code_challenge_methods_supported in Discovery.
  • Add at_hash to id_token to bind it to the access token.
  • Validate iss when verifying access tokens internally.

None of this is exotic — it is the next page of the same minimal flow.


Auth Fly logo

Auth Fly

Open auth construction kit

About Auth Fly