Sub-Task #254
Updated by Bricklou 26 days ago
Support multi-provider OIDC configuration, env/config-file based (not DB-backed) — matches how Grafana (`GF_AUTH_GENERIC_OAUTH_*` / named provider sections) and Outline (`OIDC_CLIENT_ID`/`OIDC_CLIENT_SECRET`/`OIDC_AUTH_URI`) do it. Primary mechanism: YAML file mounted via k8s ConfigMap/Secret volume, path given by `OIDC_PROVIDERS_FILE` (GitOps-friendly, readable, diffable). Fallback: `OIDC_PROVIDERS` env var with the same structure as JSON (safer than YAML for a single-line env var). Parsed at startup into in-memory provider values, following the existing `Config::from_env` pattern (apps/server/cli/src/config.rs). Client secrets stay in env/k8s Secret, not the DB — no encryption-at-rest or admin-CRUD/drift problem to solve. No DB entity/migration needed. Format spec: ```yaml <pre> # oidc-providers.yaml - id: google name: Google issuer_url: https://accounts.google.com # discovery doc = {issuer_url}/.well-known/openid-configuration client_id: xxxxx.apps.googleusercontent.com client_secret: GOCSPX-xxxxx scopes: [openid, email, profile] icon: google # slug into github.com/homarr-labs/dashboard-icons - id: keycloak name: Company SSO issuer_url: https://sso.example.com/realms/kubestro client_id: kubestro-dashboard client_secret: s3cr3t scopes: [openid, email] icon_url: https://sso.example.com/icon.svg # override for providers not in the known icon set ``` </pre> - `id`: stable slug, used in redirect URL (`/auth/oidc/{id}/callback`) and in the discovery-endpoint response. - `issuer_url`: OIDC issuer identifier, not the discovery endpoint itself — backend fetches `{issuer_url}/.well-known/openid-configuration` at startup to resolve authorize/token/jwks endpoints (standard OIDC discovery). - `icon`: slug resolved against homarr-labs/dashboard-icons ([https://github.com/homarr-labs/dashboard-icons](https://github.com/homarr-labs/dashboard-icons)), (https://github.com/homarr-labs/dashboard-icons), served via their CDN. `icon_url`: explicit override for custom/self-hosted providers not in that set.