Skip to main content
Pylon can be the identity provider that other systems sign into. Internal tools, microservices, or third-party SaaS that accept any OIDC IdP point at Pylon’s discovery doc. They treat the id_tokens Pylon issues as the identity layer.

What ships

The full auth-code and PKCE flow:

Security stance

  • PKCE S256 is REQUIRED for every authorize request. Pylon rejects plain per 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 (with PYLON_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 rotation
  • kty: "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