What ships
The full auth-code and PKCE flow:Security stance
- PKCE S256 is REQUIRED for every authorize request. Pylon rejects
plainper OAuth 2.1 and rejects a request with no PKCE. - redirect_uri must match the client’s registered list by exact string compare. Pylon allows no path coercion, suffix matching, or scheme upgrades (a common OIDC open-redirect risk).
- client_id and client_secret are constant-time compared. Public clients (no secret in registration) authenticate via PKCE alone.
- id_token claims:
iss,sub,aud,exp(10 min),iat,nonce(when supplied at /authorize),email,email_verified,name(subject to requested scopes). - access_token is opaque random (32-byte base64url), TTL 1 hour.
- refresh_token is not issued. Clients redo the auth-code flow when the access_token expires. This keeps the surface small and removes a class of long-lived bearer leak.
Configuration
PYLON_OIDC_CLIENTS is a JSON array of {client_id, client_secret?, redirect_uris[]}. client_secret is optional — omit it for SPAs / native apps that authenticate via PKCE only.
Signing key
On first start (withPYLON_OIDC_ISSUER set), Pylon generates a 2048-bit RSA key, persists it as PKCS#8 PEM at PYLON_OIDC_KEY_PATH, and chmods the file to 0600 so it is not world-readable. Pylon reuses the same key across restarts, so issued id_tokens stay verifiable.
The JWKS endpoint publishes the matching public key with:
kid= first 16 hex chars of SHA-256(modulus) — stable across restarts, changes on rotationkty: "RSA",alg: "RS256",use: "sig"n+e= base64url-no-pad-encoded big-endian integers
Auth-code flow
A typical end-to-end exchange:Userinfo claim projection
/oidc/userinfo projects the User row through the same auth.user.expose / auth.user.hide config that protects /api/auth/session from leaking secrets. passwordHash and underscore-prefixed fields never reach a downstream service through userinfo.
Claims returned per scope:
Where to go next
- JWT sessions — minting the tokens app-internal services verify
- SSO — the other direction (external IdPs signing INTO Pylon)
- Sessions — the cookie that gates
/oidc/authorize