feat(security): full OAuth 2.1 / OpenID Connect server and OIDC relying-party client

Authorization server: consent and scopes, OIDC (nonce, auth_time, acr, sid,
at_hash, signed userinfo, RP-initiated and back-channel logout), managed
refresh tokens with rotation and reuse detection, RFC 9068 JWT access tokens,
DPoP, PAR, device grant, token exchange, private_key_jwt, RFC 7591/7592
registration, RFC 9207 iss, signing keyring with rotation.

State is DB-backed through a new lookup.OAuthGrantStore (procedure and direct
backends, four dialect DDLs, conformance cases).

Client side: WithOIDC discovery, PKCE, nonce, id_token validation, OAuth2LogoutURL.

PeekRefresh now returns already rotated tokens so RotateRefresh can detect reuse.

Docs: OAUTH2_SERVER.md, oauth2_full_example.go, breaking_changes.md step 8.
This commit is contained in:
Hein
2026-10-01 14:42:12 +02:00
parent f54b707040
commit 640faeeeaf
51 changed files with 8682 additions and 1125 deletions
+35
View File
@@ -61,6 +61,8 @@ const (
OpOAuthExchangeCode Op = "oauth_exchange_code"
OpOAuthIntrospect Op = "oauth_introspect"
OpOAuthRevoke Op = "oauth_revoke"
OpOAuthUpdateClient Op = "oauth_update_client"
OpOAuthDeleteClient Op = "oauth_delete_client"
OpOAuthGetOrCreateUser Op = "oauth_get_or_create_user"
OpOAuthCreateSession Op = "oauth_create_session"
@@ -68,6 +70,22 @@ const (
OpOAuthUpdateRefreshToken Op = "oauth_update_refresh_token" //nolint:gosec // operation name, not a credential
OpOAuthGetUser Op = "oauth_get_user"
OpOAuthSaveConsent Op = "oauth_save_consent"
OpOAuthGetConsent Op = "oauth_get_consent"
OpOAuthRevokeConsent Op = "oauth_revoke_consent"
OpOAuthSaveRefresh Op = "oauth_save_refresh" //nolint:gosec // operation name, not a credential
OpOAuthRotateRefresh Op = "oauth_rotate_refresh" //nolint:gosec // operation name, not a credential
OpOAuthPeekRefresh Op = "oauth_peek_refresh" //nolint:gosec // operation name, not a credential
OpOAuthRevokeRefreshFamily Op = "oauth_revoke_refresh_family" //nolint:gosec // operation name, not a credential
OpOAuthRevokeRefreshByUser Op = "oauth_revoke_refresh_session" //nolint:gosec // operation name, not a credential
OpOAuthCreateDevice Op = "oauth_create_device"
OpOAuthDeviceByUserCode Op = "oauth_device_by_user_code"
OpOAuthDeviceDecide Op = "oauth_device_decide"
OpOAuthDevicePoll Op = "oauth_device_poll"
OpOAuthSavePAR Op = "oauth_save_par"
OpOAuthConsumePAR Op = "oauth_consume_par"
OpOAuthSeenJTI Op = "oauth_seen_jti"
OpPasskeyStore Op = "passkey_store"
OpPasskeyGet Op = "passkey_get"
OpPasskeyUpdateCounter Op = "passkey_update_counter"
@@ -144,11 +162,28 @@ func AllOps() []Op {
OpOAuthExchangeCode,
OpOAuthIntrospect,
OpOAuthRevoke,
OpOAuthUpdateClient,
OpOAuthDeleteClient,
OpOAuthGetOrCreateUser,
OpOAuthCreateSession,
OpOAuthGetRefreshToken,
OpOAuthUpdateRefreshToken,
OpOAuthGetUser,
OpOAuthSaveConsent,
OpOAuthGetConsent,
OpOAuthRevokeConsent,
OpOAuthSaveRefresh,
OpOAuthRotateRefresh,
OpOAuthPeekRefresh,
OpOAuthRevokeRefreshFamily,
OpOAuthRevokeRefreshByUser,
OpOAuthCreateDevice,
OpOAuthDeviceByUserCode,
OpOAuthDeviceDecide,
OpOAuthDevicePoll,
OpOAuthSavePAR,
OpOAuthConsumePAR,
OpOAuthSeenJTI,
OpPasskeyStore,
OpPasskeyGet,
OpPasskeyUpdateCounter,