@
Summary
Add a generic, admin-configurable external OIDC/OAuth2 login provider to PoracleWeb, so any self-hoster can point the app at their own identity provider. It mirrors the existing Discord login flow, parameterized by config.
PGAN context: this lets PoracleWeb (alerts.pogoalerts.net) delegate login to the PogoAlerts OAuth2/OIDC server (pogoalerts.net) for true single sign-on across the PogoAlerts main site, ReactMap, and PoracleWeb — but the feature is provider-agnostic.
Approach
A parameterized twin of the Discord OAuth flow. Provider config (authorize/token/userinfo URLs, client id/secret, claim mapping, display name) comes from env/appsettings — same two-layer model as Discord: server config = "configured", plus an enable_oidc site setting = admin runtime toggle. After userinfo returns, a configurable identity claim (default discord_id) is looked up in the Poracle human table exactly like the Discord path; existing role gating is reused; the existing internal JWT is minted via IJwtService. No change to how PoracleWeb issues/validates its own tokens.
Scope
Backend
Frontend (ClientApp)
Tests
Out of scope (later passes)
- ReactMap install of the prewritten PogoAlerts Passport strategy
- PogoAlerts IdP: cross-subdomain
.pogoalerts.net SSO cookie; secret hygiene
- Telegram parity in PogoAlerts (Discord-only for now)
@
@
Summary
Add a generic, admin-configurable external OIDC/OAuth2 login provider to PoracleWeb, so any self-hoster can point the app at their own identity provider. It mirrors the existing Discord login flow, parameterized by config.
PGAN context: this lets PoracleWeb (
alerts.pogoalerts.net) delegate login to the PogoAlerts OAuth2/OIDC server (pogoalerts.net) for true single sign-on across the PogoAlerts main site, ReactMap, and PoracleWeb — but the feature is provider-agnostic.Approach
A parameterized twin of the Discord OAuth flow. Provider config (authorize/token/userinfo URLs, client id/secret, claim mapping, display name) comes from env/appsettings — same two-layer model as Discord: server config = "configured", plus an
enable_oidcsite setting = admin runtime toggle. After userinfo returns, a configurable identity claim (defaultdiscord_id) is looked up in the Poraclehumantable exactly like the Discord path; existing role gating is reused; the existing internal JWT is minted viaIJwtService. No change to how PoracleWeb issues/validates its own tokens.Scope
Backend
OidcSettingsconfig class (URLs, client id/secret, scopes, claim mapping, PKCE flag, provider name)Program.csenv var bridge (OIDC_*->Oidc__*) + DI binding; document in.env.example(no startup hard-validation — provider is optional)AuthController:GET /api/auth/oidc/login(state + PKCE) andGET /api/auth/oidc/callback(code exchange -> userinfo -> human lookup -> role gate -> JWT)Providers()with anoidcblock (configured / enabledByAdmin / providerName)enable_oidcinSettingsMigrationService(BooleanKeys + CategoryMap)Frontend (ClientApp)
AuthProvidersmodel gainsoidcauth.service.tsloginWithOidc();/auth/oidc/callbackroute (reusesCallbackComponent)oidc_*error codes in login + callback mapsenable_oidctoggleAUTH.SIGN_IN_OIDC,AUTH.ERR_OIDC_*,ADMIN_SETTINGS.*_OIDC)Tests
/oidc/loginredirect/stateloginWithOidc()+ oidc button visibility specsOut of scope (later passes)
.pogoalerts.netSSO cookie; secret hygiene@