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;
algnever 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_methodat/authorize. - Verify
code_verifierat/tokenwith constant-time comparison. - Advertise
code_challenge_methods_supportedin Discovery. - Add
at_hashto id_token to bind it to the access token. - Validate
isswhen verifying access tokens internally.
None of this is exotic — it is the next page of the same minimal flow.