Admin SSO (OIDC)
The admin console supports single sign-on via any OpenID Connect provider (Google Workspace, Entra ID, Okta, Dex, …) using the Authorization Code flow with PKCE (S256), a state CSRF token and a nonce. The feature is opt-in: with no configuration the console stays on the password flow, unchanged.
Enabling
All four values must be set — anything less keeps SSO off:
Env / config.yaml (admin:) | Meaning |
|---|---|
YABANIN_ADMIN_OIDC_ISSUER / oidc_issuer | Provider issuer URL, e.g. https://accounts.google.com |
YABANIN_ADMIN_OIDC_CLIENT_ID / oidc_client_id | OAuth client id |
YABANIN_ADMIN_OIDC_CLIENT_SECRET / oidc_client_secret | OAuth client secret |
YABANIN_ADMIN_OIDC_REDIRECT_URL / oidc_redirect_url | e.g. https://admin.example.com/auth/oidc/callback |
The provider's discovery document and JWKS are fetched at startup; a failure logs loudly and keeps the console on the password flow — never a half-working SSO mount.
The flow
GET /auth/oidc/login— issues a one-timestate/nonce/PKCE triple in a 10-minute HttpOnly+Secure cookie (SameSite=Lax: the callback arrives as a top-level navigation) and redirects to the provider.GET /auth/oidc/callback— constant-time state check, code exchange with the PKCE verifier, ID token verification (signature against the provider's JWKS, issuer, audience, expiry, nonce).- User mapping — fail-closed: the verified email must match an
existing active admin user. SSO never provisions accounts, never
widens roles; the issued session is byte-for-byte the password-flow
session (same HMAC cookie, same
IsRoot).
The one-time cookie is cleared on every callback outcome — its secrets are single-use by construction.
Security contract
email_verifiedis required. A provider asserting an email without verifying it does not log anyone in.- No auto-provisioning. Unknown emails get the same refusal as disabled accounts — no user enumeration, no signup-by-SSO.
- Nonce binds the ID token to this login. A token minted for another session cannot be replayed.
- No open redirects. Success always lands on
/; the login redirect always targets the configured issuer. - The local part of emails never reaches the logs; only the domain is recorded on a mapping refusal.