oauth2 package implements the Authorization Code flow with PKCE and OIDC
support. Four provider presets are built in: Google, GitHub, Facebook, and Zalo.
Any other provider is configured as a plain ClientRegistration.
Import
Quick setup
securityhttp.SessionAuthentication middleware.
The callback route (/login/oauth2/code/*) is intentionally CSRF-exempt: the
single-use, session-bound state parameter is the CSRF defense for the
authorization-code flow. If you mount web/csrf, exclude that path — securityhttp
does not add this exclusion automatically. The nonce check is only enforced
when the authorization request set one (non-empty), and state is validated
before the code exchange, closing an auth-code-injection window:
Provider presets
oauth2.Preset(t oauth2.ProviderType) returns the fixed endpoints, default
scopes, and subject attribute for a known provider; oauth2.NewRegistration
uses it internally to build a validated ClientRegistration.
NewRegistration only works for these four known providers — Preset has no
entry for ProviderGeneric, so a custom provider is built as a plain
ClientRegistration (see below).
Custom provider
Build theClientRegistration directly. Scopes containing "openid" make it
an OIDC registration (IsOIDC() returns true), which Validate() then
requires a JWKSetURI and Issuer for:
"openid" (and JWKSetURI/Issuer) for a plain OAuth2 provider — the
callback then calls UserInfoURI instead of validating an ID token.
AllowInsecure: true permits http:// endpoints for localhost dev fixtures.
Leave it false (the default) in production; every endpoint is otherwise
required to be https://.
PKCE
PKCE (Proof Key for Code Exchange) is always enabled. Acode_verifier is
generated per authorization request and stored in the session. The
code_challenge is sent in the authorization redirect as S256.
No configuration is needed — PKCE cannot be disabled.
OIDC
A registration is OIDC when itsScopes include "openid"
(ClientRegistration.IsOIDC()). For an OIDC registration the callback
validates the ID token instead of calling the userinfo endpoint.
ID token validation:
- Signature verified against the provider’s JWKS
audmust matchClientIDexpmust be present and in the future (required, not just checked if set)issmust match the registration’sIssuernoncemust match the value generated for that authorization request (ErrNonceMismatchotherwise)
State parameter
A single-use, session-bound state parameter is generated per authorization request. It is verified on callback and immediately invalidated, preventing CSRF attacks on the OAuth2 flow.Errors
Failures are sentinel errors, matchable witherrors.Is:
LoginConfig.OnFailure receives these (default: write a 401). The provider’s
error_description is never reflected back to the client.
Granted authorities
By default every successful login is grantedOAUTH2_USER plus one
SCOPE_<x> authority per granted OAuth2 scope
(oauth2.DefaultAuthoritiesMapper()). Supply LoginConfig.AuthoritiesMap to
map provider attributes to your own roles:
Session principal
After a successful callback, the OAuth2 subject (e.g."12345678" for Google)
is stored as the session principal. On subsequent requests,
SessionAuthentication calls UserService.LoadUser(subject).
Implement UserService to synthesize a user from the subject if it doesn’t
exist in your database, or create a row on first login:
AuthorizedClient
After a successful login, the access/refresh token pair is stored server-side, keyed by session and registration id, in anAuthorizedClientRepository — it
is never placed on the principal, a cookie, or a log. Load it with the
session belonging to the current request:
client.AccessExpired(time.Now()) reports whether the access token has
expired (a zero expiry, i.e. unknown lifetime, is treated as not expired).