- Shipped
- November 15, 2026 at 2:41 AM UTC
- Author
- Kamo
- Commit
- c75df92
federation/: an OIDC relying party (PKCE S256 + nonce + state) for Google / Microsoft / Apple / LinkedIn, and OAuth2 adapters for GitHub (/user + primary verified /user/emails) and Facebook (/me + appsecret_proof), behind one ProviderAdapter interface. id_tokens are checked against each provider's JWKS (cached, early refetch on an unknown kid at most once a minute), issuer, audience/azp, expiry/iat and nonce; Microsoft's issuer is checked against the token's own tid and identities key on tenant issuer + oid, never on its email. Apple's client secret is an ES256 JWT signed from the registry's .p8 (150 days, cached); its name arrives once, as appleUser. Start/link/signup records live in Redis (FEDST/FEDLK/FEDSU/FEDLS), single use, spent on the way in and restored with their remaining TTL (and the proven identity) on a fault that is not the member's - never after a wrong binding, a refused code or a forged token. Linking: lookup by (issuer, subject, connection_key); an existing email answers NOT_LINKED and demands proof - password + the account's second factor, or a code to the ACCOUNT email (5 tries, 3 sends); LINK from a signed-in session demands the same. Every connect/disconnect mails the account email and writes IDENTITY_LINKED / IDENTITY_UNLINKED. A linked identity is handed to the password path's downstream (FederatedSignInCompleter -> account gates, host/picker rules, access rules, SignInCompletionService) plus the org's policy (provider allowed for this member's audience; MFA demanded but not enrolled = refused here). Not charged to the lockout ladder; per-IP callback/link budget instead. Clients come from PlatformOAuthClientResolver for the *_SIGNIN types - an org's own app only on its own verified domain - and are offered only at config_json.signinStatus ENABLED (CONFIGURED = platform org only). None is configured, so nothing visible changes.
