Authelia's forward_auth (what this repo already sets up) gates a whole site
behind a login page before the request reaches it. This is the opposite
direction: an app with its own "Enable OpenID"/SSO setting delegating ITS
login to Authelia, via Authelia's separate OIDC PROVIDER feature, which
this repo had no support for at all.
_authelia_ensure_oidc_provider() enables it once, idempotently: generates
an HMAC secret (injected via a _FILE env var, same convention as the
existing jwt/session/storage secrets) and an RSA signing keypair, then
writes identity_providers.oidc into configuration.yml. The RSA private key
has to be inlined as PEM directly in that file — Authelia's jwks schema has
no file-path or env-var option for it — so configuration.yml gets chmod 600
once OIDC is enabled, unlike before when it held no raw secrets.
_authelia_add_oidc_client() registers an app: presets for ActualBudget
(/openid/callback) and Vaultwarden (/identity/connect/oidc-signin, and
confirmed its SSO support is now native/upstream, not fork-only) fill in
the redirect URI automatically; "Other/custom" covers anything else. Each
app gets its own Client ID and a random secret (shown once, only the
pbkdf2 hash is stored), and the output tells the operator exactly what to
paste back into that app's own OpenID dialog or .env — including
Vaultwarden's exact SSO_* env vars, not just generic OIDC endpoint URLs.
Wired into the existing "Authelia already exists" menu as a new option,
alongside "add another protected domain" and "reconfigure from scratch".
Exact CLI output formats, default filenames, and YAML schema were verified
against Authelia's own CLI source/docs (crypto rand's "Random Value: "
label, crypto hash generate pbkdf2's "Random Password:"/"Digest:" labels,
crypto pair rsa generate's private.pem/public.pem defaults) rather than
guessed, since a wrong assumption here means a cryptic startup failure or
broken secret extraction. The YAML manipulation (client-list insertion,
domain extraction from session.cookies) was tested end-to-end against the
real mikefarah/yq binary against a realistic mock config, which caught a
real bug (extracting the wrong awk field for the domain, "domain:" instead
of the actual value) before it shipped.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn