plMail could only sign people in with a local password. On an install that
already runs Authentik or Keycloak, that is one more account and password
per person, outside the provider's access policy.
A second authenticator on the `main` firewall, beside the password form.
Both end in the same token for the same User, so the user checker, the login
throttle and TOTP two-factor apply unchanged. Authorization code flow with
PKCE, state and nonce on league/oauth2-client's GenericProvider; endpoints
come from the provider's discovery document.
- Set up under a new Admin → SSO tab; the OIDC_* variables are the fallback
for an install configured from its compose file, and a saved provider wins
whole. This lets an administrator who points it at a provider of their own
sign in as any account without a second factor; the security model says so.
- The ID token's signature is not verified: it only ever comes from the
token endpoint over TLS (OIDC Core § 3.1.3.7 step 6). So the issuer and
endpoints must be https and no request to the provider follows a redirect.
Accepting an ID token from anywhere else needs JWKS verification first.
- An account is linked by (issuer, sub). The address is used for the first
link only, and only when the provider reports it verified.
- Auto-creation is off by default and creates an ordinary account with no
usable password.
- app:user:oidc-unlink forgets a link from the console, for somebody deleted
and re-added at the provider.
Migration: two nullable columns and a unique index on `user`, and a one-row
table `oidc_config`. Nothing backfilled; reversible.
Not run: Playwright on this branch. No automated test makes a round trip
against a real provider; that was checked by hand on a local test stack.
Closes#91
Co-Authored-By: Paul Lützner <mail@pluetzner.de>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>