oauth2

package
v0.25.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// EventClientCreated is dispatched when a new OAuth client is registered.
	EventClientCreated = "oauth2:client:created"

	// EventClientUpdated is dispatched when an existing OAuth client is updated.
	EventClientUpdated = "oauth2:client:updated"

	// EventClientDeleted is dispatched when an OAuth client is deleted.
	EventClientDeleted = "oauth2:client:deleted"

	// EventAuthorizeSuccess is dispatched when an authorization request successfully issues an authorization code.
	EventAuthorizeSuccess = "oauth2:authorize:success"

	// EventAuthorizeFailed is dispatched when an authorization request fails validation or is rejected.
	EventAuthorizeFailed = "oauth2:authorize:failed"

	// EventTokenIssued is dispatched when an access token, refresh token, or ID token is issued.
	EventTokenIssued = "oauth2:token:issued"

	// EventTokenRefreshed is dispatched when a refresh token exchange succeeds with token rotation.
	EventTokenRefreshed = "oauth2:token:refreshed"

	// EventTokenRevoked is dispatched when an access token or refresh token is explicitly revoked.
	EventTokenRevoked = "oauth2:token:revoked"

	// EventConsentGranted is dispatched when an end-user approves requested scopes for a client.
	EventConsentGranted = "oauth2:consent:granted"

	// EventConsentRevoked is dispatched when an end-user revokes previously granted scopes for a client.
	EventConsentRevoked = "oauth2:consent:revoked"

	// EventSessionEnded is dispatched when an RP-Initiated Logout flow completes.
	EventSessionEnded = "oauth2:session:ended"
)

Event topic constants dispatched on the shared plugin.Context EventBus.

View Source
const (
	// ScopeOpenID requests an OpenID Connect ID Token and enables identity workflows.
	ScopeOpenID = "openid"

	// ScopeProfile grants access to the End-User's default Profile Claims (name, picture, etc.).
	ScopeProfile = "profile"

	// ScopeEmail grants access to the email and email_verified claims.
	ScopeEmail = "email"

	// ScopeOffline requests issuance of an OAuth 2.1 Refresh Token (offline_access).
	ScopeOffline = "offline_access"

	// ScopePhone grants access to phone_number and phone_number_verified claims.
	ScopePhone = "phone"

	// ScopeAddress grants access to the address claim.
	ScopeAddress = "address"
)

Standard OpenID Connect (OIDC Core 1.0) and OAuth 2.1 Scope Constants.

View Source
const (
	// PromptNone instructs the server not to display any authentication or consent UI.
	PromptNone = "none"

	// PromptLogin forces the server to prompt the user for re-authentication.
	PromptLogin = "login"

	// PromptConsent forces the server to prompt the user for consent.
	PromptConsent = "consent"

	// PromptSelectAccount prompts the user to select a user account.
	PromptSelectAccount = "select_account"
)

Prompt types for OpenID Connect authorization requests.

View Source
const (
	// CodeChallengeMethodS256 represents SHA-256 hashed code challenge (mandatory in OAuth 2.1).
	CodeChallengeMethodS256 = "S256"

	// CodeChallengeMethodPlain represents plain text challenge (deprecated and forbidden in OAuth 2.1).
	CodeChallengeMethodPlain = "plain"
)

CodeChallengeMethod constants for PKCE (RFC 7636).

View Source
const (
	ExtraKeyClientID         = "oauth2:client_id"
	ExtraKeyClientSecret     = "oauth2:client_secret"
	ExtraKeyUserID           = "oauth2:user_id"
	ExtraKeySessionID        = "oauth2:session_id"
	ExtraKeyScopes           = "oauth2:scopes"
	ExtraKeyRedirectURI      = "oauth2:redirect_uri"
	ExtraKeyCodeChallenge    = "oauth2:code_challenge"
	ExtraKeyNonce            = "oauth2:nonce"
	ExtraKeyResource         = "oauth2:resource"
	ExtraKeyClaims           = "oauth2:claims"
	ExtraKeyAccessToken      = "oauth2:access_token"
	ExtraKeyRefreshToken     = "oauth2:refresh_token"
	ExtraKeyIDToken          = "oauth2:id_token"
	ExtraKeyAuthTime         = "oauth2:auth_time"
	ExtraKeyTokenType        = "oauth2:token_type"
	ExtraKeyFamilyID         = "oauth2:family_id"
	ExtraKeyInteractiveQuery = "oauth2:interactive_query"
)

Dynamic metadata keys used across Extra map bags and event payloads.

View Source
const (
	ContextKeyOAuthClient       = "oauth2:current_client"
	ContextKeyOAuthToken        = "oauth2:current_token"
	ContextKeyOAuthUser         = "oauth2:current_user"
	ContextKeyOAuthAuthCode     = "oauth2:current_auth_code"
	ContextKeyOAuthRefreshToken = "oauth2:current_refresh_token"
)

ContextKey constants for storing and retrieving OAuth 2.1 objects in plugin.Context.

View Source
const PluginID = "oauth2"

PluginID is the unique string identifier for the OAuth 2.1 Provider plugin ("oauth2").

View Source
const (
	TokenIntrospectContextKey contextKey = "oauth2_token_introspect"
)

Variables

View Source
var (
	// ErrDecryptionFailed is returned when ciphertext fails authenticated AES-GCM decryption or authentication tag check.
	ErrDecryptionFailed = errors.New("oauth2/crypto: decryption failed or invalid authentication tag")

	// ErrInvalidKeyLength is returned when a symmetric encryption key does not meet requirements.
	ErrInvalidKeyLength = errors.New("oauth2/crypto: invalid key length (expected 32 bytes for AES-256)")
)
View Source
var (
	// ErrClientNotFound is returned when an OAuth client cannot be found in storage.
	ErrClientNotFound = errors.New("oauth2: client not found")

	// ErrClientDisabled is returned when an OAuth client has been administratively disabled.
	ErrClientDisabled = errors.New("oauth2: client is disabled")

	// ErrInvalidClient is returned when client credentials (ID or secret) are invalid or mismatched.
	ErrInvalidClient = errors.New("oauth2: invalid client credentials")

	// ErrInvalidClientSecret is returned when the provided client secret does not match the stored secret.
	ErrInvalidClientSecret = errors.New("oauth2: invalid client secret")

	// ErrInvalidRedirectURI is returned when the redirect_uri does not match any registered URI for the client.
	ErrInvalidRedirectURI = errors.New("oauth2: invalid or unregistered redirect_uri")

	// ErrInvalidResponseType is returned when response_type is not supported (OAuth 2.1 requires 'code').
	ErrInvalidResponseType = errors.New("oauth2: unsupported response_type (must be 'code')")

	// ErrInvalidGrantType is returned when grant_type is unsupported or not permitted for the client.
	ErrInvalidGrantType = errors.New("oauth2: unsupported or unauthorized grant_type")

	// ErrInvalidAuthorizationCode is returned when the authorization code is invalid, already consumed, or not found.
	ErrInvalidAuthorizationCode = errors.New("oauth2: invalid or already consumed authorization code")

	// ErrAuthorizationCodeExpired is returned when the authorization code has exceeded its validity lifetime.
	ErrAuthorizationCodeExpired = errors.New("oauth2: authorization code has expired")

	// ErrInvalidPKCE is returned when code_verifier is missing or fails SHA-256 S256 comparison against code_challenge.
	ErrInvalidPKCE = errors.New("oauth2: invalid code_verifier or failed PKCE verification")

	// ErrInvalidCodeChallengeMethod is returned when code_challenge_method is not 'S256' (OAuth 2.1 disallows 'plain').
	ErrInvalidCodeChallengeMethod = errors.New("oauth2: only 'S256' code_challenge_method is supported in OAuth 2.1")

	// ErrInvalidRefreshToken is returned when a refresh token cannot be found or is expired.
	ErrInvalidRefreshToken = errors.New("oauth2: invalid or expired refresh token")

	// ErrRefreshTokenRevoked is returned when an already revoked refresh token is presented (potential token theft).
	ErrRefreshTokenRevoked = errors.New("oauth2: refresh token has been revoked")

	// ErrInvalidAccessToken is returned when an access token cannot be validated or is expired/revoked.
	ErrInvalidAccessToken = errors.New("oauth2: invalid or expired access token")

	// ErrConsentRequired is returned in prompt=none when the user has not pre-consented to the requested scopes.
	ErrConsentRequired = errors.New("oauth2: consent required")

	// ErrLoginRequired is returned in prompt=none when the user is not actively authenticated.
	ErrLoginRequired = errors.New("oauth2: login required")

	// ErrAccessDenied is returned when the resource owner or authorization server denied the request.
	ErrAccessDenied = errors.New("oauth2: access denied")

	// ErrInvalidScope is returned when the requested scope is malformed or exceeds authorized client scopes.
	ErrInvalidScope = errors.New("oauth2: requested scope is invalid or exceeds client permissions")

	// ErrInvalidRequest is returned when required parameters are missing or malformed.
	ErrInvalidRequest = errors.New("oauth2: invalid request parameters")

	// ErrUnauthorizedClient is returned when the client is not authorized to use the requested grant type.
	ErrUnauthorizedClient = errors.New("oauth2: client is not authorized to use this grant type")

	// ErrDynamicRegistrationDisabled is returned when dynamic client registration is disabled by configuration.
	ErrDynamicRegistrationDisabled = errors.New("oauth2: dynamic client registration is disabled")

	// ErrInvalidSignature is returned when an HMAC query signature on interactive redirects fails verification.
	ErrInvalidSignature = errors.New("oauth2: invalid interactive query signature")
)

Sentinel error definitions for OAuth 2.1 and OpenID Connect flows.

View Source
var (
	// ErrInvalidJWT is returned when a JWT token is malformed, has invalid signature or has expired.
	ErrInvalidJWT = errors.New("oauth2/signer: invalid JWT token")

	// ErrJWTExpired is returned when a JWT token's 'exp' claim is in the past.
	ErrJWTExpired = errors.New("oauth2/signer: JWT token has expired")
)

Functions

func ComputeCodeChallenge

func ComputeCodeChallenge(verifier string) string

ComputeCodeChallenge computes the PKCE S256 code challenge for a given code verifier.

OAuth 2.1 RFC 7636 Section 4.2 specifies:

code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

func ComputeLeftHash

func ComputeLeftHash(value string) string

ComputeLeftHash computes the OIDC at_hash or c_hash claim value for ID Tokens (RFC 7636 / OIDC Core 1.0).

It takes the first 128 bits (16 bytes) of the SHA-256 hash and encodes it in Base64URL without padding.

func Decrypt

func Decrypt(encodedCiphertext string, key []byte) ([]byte, error)

Decrypt decrypts Base64URL-encoded ciphertext produced by Encrypt using AES-256-GCM.

func DeriveAESKey

func DeriveAESKey(secret string) []byte

DeriveAESKey derives a 32-byte cryptographic key for AES-256 from an arbitrary secret string.

func DerivePairwiseSubject

func DerivePairwiseSubject(pairwiseSecret, sectorIdentifier, userID string) string

DerivePairwiseSubject generates a deterministic pseudonymous subject identifier (sub claim) for a user given a sector identifier (or client redirect host) and pairwise secret.

OIDC Core 1.0 Section 8.1:

sub = HMAC-SHA256(pairwiseSecret, sector_identifier + ":" + user_id)

func Encrypt

func Encrypt(plaintext []byte, key []byte) (string, error)

Encrypt encrypts plain text data using AES-256-GCM authenticated encryption.

It generates a cryptographically random 12-byte nonce and returns the concatenated nonce + ciphertext + GCM auth tag encoded in Base64URL without padding.

func GenerateRandomString

func GenerateRandomString(byteLen int) (string, error)

GenerateRandomString generates a cryptographically secure random string of specified byte length, encoded in Base64URL without padding.

func HashSecret

func HashSecret(secret string) string

HashSecret computes a deterministic SHA-256 hash string for a client secret.

func HashToken

func HashToken(token string) string

HashToken computes a deterministic SHA-256 hash string for an access token or refresh token.

func SignOAuthQuery

func SignOAuthQuery(query, secret string) string

SignOAuthQuery calculates an HMAC-SHA256 signature for interactive query parameters.

func VerifyOAuthQuery

func VerifyOAuthQuery(query, signature, secret string) bool

VerifyOAuthQuery verifies the HMAC-SHA256 signature of an interactive query string.

func VerifyPKCE

func VerifyPKCE(verifier, challenge, method string) bool

VerifyPKCE validates an incoming code verifier against a stored code challenge and method.

In strict OAuth 2.1 mode, only the "S256" challenge method is permitted. Comparison is performed using constant-time comparison to prevent timing attacks.

Types

type AccessTokenType

type AccessTokenType string

AccessTokenType defines the format of the issued Access Token.

const (
	// AccessTokenTypeJWT issues structured and signed JSON Web Tokens per RFC 9068.
	AccessTokenTypeJWT AccessTokenType = "jwt"

	// AccessTokenTypeOpaque issues cryptographically random opaque tokens persisted in storage.
	AccessTokenTypeOpaque AccessTokenType = "opaque"
)

type AuthorizeFailedEventPayload

type AuthorizeFailedEventPayload struct {
	// ClientID is the client ID involved in the failed request, if known.
	ClientID string `json:"client_id,omitempty"`

	// Error is the error description of the failure.
	Error string `json:"error"`

	// RedirectURI is the callback URI if available for error redirection.
	RedirectURI string `json:"redirect_uri,omitempty"`

	// Timestamp is the moment the failure occurred.
	Timestamp time.Time `json:"timestamp"`
}

AuthorizeFailedEventPayload represents the payload dispatched when an authorization request fails.

type AuthorizeParams

type AuthorizeParams struct {
	ClientID            string `json:"client_id"`
	RedirectURI         string `json:"redirect_uri"`
	ResponseType        string `json:"response_type"`
	CodeChallenge       string `json:"code_challenge"`
	CodeChallengeMethod string `json:"code_challenge_method"`
	Scope               string `json:"scope"`
	State               string `json:"state"`
	Nonce               string `json:"nonce,omitempty"`
	Prompt              string `json:"prompt,omitempty"`
	Resource            string `json:"resource,omitempty"`
	SessionID           string `json:"session_id,omitempty"`
	UserID              string `json:"user_id,omitempty"`
	plugin.ExtraContainer
}

AuthorizeParams defines input parameters for initiating the OAuth 2.1 authorization code flow.

type AuthorizeResult

type AuthorizeResult struct {
	RedirectURI  string `json:"redirect_uri"`
	Code         string `json:"code,omitempty"`
	State        string `json:"state,omitempty"`
	Issuer       string `json:"iss,omitempty"`
	IsRedirect   bool   `json:"is_redirect"`
	NeedsLogin   bool   `json:"needs_login"`
	NeedsConsent bool   `json:"needs_consent"`
}

AuthorizeResult represents the outcome of an authorization request.

type AuthorizeSuccessEventPayload

type AuthorizeSuccessEventPayload struct {
	// ClientID is the client ID that received the authorization code.
	ClientID string `json:"client_id"`

	// UserID is the authenticated user ID granting authorization.
	UserID string `json:"user_id"`

	// RedirectURI is the validated callback redirect URI.
	RedirectURI string `json:"redirect_uri"`

	// Scopes is the list of granted scopes.
	Scopes []string `json:"scopes"`

	// Code is the issued authorization code string.
	Code string `json:"code"`

	// Timestamp is the moment the code was issued.
	Timestamp time.Time `json:"timestamp"`
}

AuthorizeSuccessEventPayload represents the payload dispatched upon successful authorization code issuance.

type ClientEventPayload

type ClientEventPayload struct {
	// Client is the OAuth client entity created, updated, or deleted.
	Client *OAuthClient `json:"client"`

	// Timestamp is the moment the event occurred.
	Timestamp time.Time `json:"timestamp"`
}

ClientEventPayload represents the payload dispatched for client lifecycle events.

type ClientType

type ClientType string

ClientType defines the category of OAuth client.

const (
	// ClientTypeConfidential represents confidential clients capable of securely storing credentials (e.g. backend servers).
	ClientTypeConfidential ClientType = "confidential"

	// ClientTypePublic represents public clients unable to securely store secrets (e.g. SPAs, mobile apps).
	ClientTypePublic ClientType = "public"
)

type Config

type Config struct {
	// Issuer is the base URL of the authorization server ("iss" claim in tokens and discovery).
	Issuer string

	// LoginPage is the relative or absolute path of the user login UI page for interactive redirection.
	LoginPage string

	// ConsentPage is the relative or absolute path of the user consent UI page for interactive redirection.
	ConsentPage string

	// Scopes is the list of supported scopes announced by the authorization server.
	Scopes []string

	// GrantTypes is the list of OAuth 2.1 grant types enabled on this server.
	GrantTypes []GrantType

	// AccessTokenType specifies whether Access Tokens are issued as RFC 9068 JWTs or opaque tokens.
	AccessTokenType AccessTokenType

	// CodeExpiresIn is the validity duration of single-use authorization codes (default: 10m).
	CodeExpiresIn time.Duration

	// AccessTokenExpiresIn is the validity duration of user access tokens (default: 1h).
	AccessTokenExpiresIn time.Duration

	// RefreshTokenExpiresIn is the validity duration of refresh tokens (default: 30 days).
	RefreshTokenExpiresIn time.Duration

	// IDTokenExpiresIn is the validity duration of OpenID Connect ID Tokens (default: 1h).
	IDTokenExpiresIn time.Duration

	// M2MAccessTokenExpiresIn is the validity duration of client_credentials access tokens (default: 2h).
	M2MAccessTokenExpiresIn time.Duration

	// AllowDynamicClientRegistration enables RFC 7591 Dynamic Client Registration endpoint.
	AllowDynamicClientRegistration bool

	// AllowUnauthenticatedClientRegistration allows client registration without an initial access token.
	AllowUnauthenticatedClientRegistration bool

	// StoreClientSecretMode defines how client secrets are persisted ("plain", "hashed", "encrypted").
	StoreClientSecretMode StoreMode

	// StoreTokensMode defines how tokens are persisted ("plain", "hashed", "encrypted").
	StoreTokensMode StoreMode

	// SecretKey is the master cryptographic key used for symmetric AES-256-GCM encryption and HMAC query signing.
	SecretKey string

	// PairwiseSecret is the cryptographic salt used to compute pairwise pseudonymous subjects.
	PairwiseSecret string

	// ValidAudiences is the list of accepted audiences for validation.
	ValidAudiences []string

	// JWTSigner is the custom or default token signer used to sign ID Tokens and JWT Access Tokens.
	JWTSigner JWTSigner

	// CustomAccessTokenClaims is an optional callback to enrich JWT Access Tokens with application-specific claims.
	CustomAccessTokenClaims CustomClaimsFunc

	// CustomIDTokenClaims is an optional callback to enrich OIDC ID Tokens with application-specific claims.
	CustomIDTokenClaims CustomClaimsFunc

	// CustomUserInfoClaims is an optional callback to enrich OIDC /userinfo endpoint responses.
	CustomUserInfoClaims CustomClaimsFunc
}

Config defines the configuration options for the OAuth 2.1 and OpenID Connect Provider plugin.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns the recommended production defaults for OAuth 2.1 and OpenID Connect.

type ConsentEventPayload

type ConsentEventPayload struct {
	// Consent is the consent record granted or revoked.
	Consent *OAuthConsent `json:"consent"`

	// Timestamp is the moment the consent event occurred.
	Timestamp time.Time `json:"timestamp"`
}

ConsentEventPayload represents the payload dispatched for user consent events.

type ConsentParams

type ConsentParams struct {
	OAuthQuery     string   `json:"oauth_query"`
	OAuthSignature string   `json:"oauth_signature"`
	UserID         string   `json:"user_id"`
	ApprovedScopes []string `json:"approved_scopes"`
	Denied         bool     `json:"denied"`
	plugin.ExtraContainer
}

ConsentParams defines input parameters for user approval or denial of requested scopes.

type ConsentResult

type ConsentResult struct {
	RedirectURI string `json:"redirect_uri"`
	Code        string `json:"code,omitempty"`
	State       string `json:"state,omitempty"`
	Issuer      string `json:"iss,omitempty"`
}

ConsentResult represents the result of processing user consent.

type ContinueAuthorizeParams

type ContinueAuthorizeParams struct {
	OAuthQuery     string `json:"oauth_query"`
	OAuthSignature string `json:"oauth_signature"`
	SessionID      string `json:"session_id"`
	UserID         string `json:"user_id"`
	plugin.ExtraContainer
}

ContinueAuthorizeParams defines input parameters when resuming authorization after login/consent.

type CustomClaimsFunc

type CustomClaimsFunc func(ctx context.Context, client *OAuthClient, user *entity.User, scopes []string) (map[string]any, error)

CustomClaimsFunc allows injecting additional custom claims into tokens or UserInfo responses.

type DeleteClientParams

type DeleteClientParams struct {
	ClientID string `json:"client_id"`
	plugin.ExtraContainer
}

DeleteClientParams defines input parameters to delete an OAuth client.

type DeleteClientResult

type DeleteClientResult struct {
	Success bool `json:"success"`
}

DeleteClientResult reports the outcome of deleting a client.

type EndSessionParams

type EndSessionParams struct {
	IDTokenHint           string `json:"id_token_hint,omitempty"`
	ClientID              string `json:"client_id,omitempty"`
	PostLogoutRedirectURI string `json:"post_logout_redirect_uri,omitempty"`
	State                 string `json:"state,omitempty"`
	SessionID             string `json:"session_id,omitempty"`
	plugin.ExtraContainer
}

EndSessionParams defines input parameters for RP-Initiated Logout.

type EndSessionResult

type EndSessionResult struct {
	RedirectURI string `json:"redirect_uri"`
}

EndSessionResult contains the redirection target after logout.

type GetClientParams

type GetClientParams struct {
	ClientID string `json:"client_id"`
	plugin.ExtraContainer
}

GetClientParams defines input parameters to lookup an OAuth client.

type GetClientResult

type GetClientResult struct {
	Client *OAuthClient `json:"client"`
}

GetClientResult contains the client entity.

type GrantType

type GrantType string

GrantType represents the authorization grant types defined in OAuth 2.1.

const (
	// GrantTypeAuthorizationCode represents the authorization code grant type (RFC 6749 / OAuth 2.1).
	GrantTypeAuthorizationCode GrantType = "authorization_code"

	// GrantTypeClientCredentials represents machine-to-machine client credentials grant type.
	GrantTypeClientCredentials GrantType = "client_credentials"

	// GrantTypeRefreshToken represents the refresh token grant type with mandatory rotation.
	GrantTypeRefreshToken GrantType = "refresh_token"
)

type HMACSigner

type HMACSigner struct {
	// contains filtered or unexported fields
}

HMACSigner is a lightweight, RFC 7519 compliant HMAC-SHA256 JWT signer.

func NewHMACSigner

func NewHMACSigner(secret string, keyID ...string) *HMACSigner

NewHMACSigner creates a new HMAC-SHA256 JWTSigner with the specified secret and optional key ID.

func (*HMACSigner) Sign

func (s *HMACSigner) Sign(ctx context.Context, claims map[string]any, expiresIn time.Duration) (string, string, error)

Sign constructs a compact serialized JWT token ("header.payload.signature") signed with HS256.

func (*HMACSigner) Verify

func (s *HMACSigner) Verify(ctx context.Context, tokenString string) (map[string]any, error)

Verify decodes and validates a compact HS256 JWT string.

type IntrospectParams

type IntrospectParams struct {
	Token         string `json:"token"`
	TokenTypeHint string `json:"token_type_hint,omitempty"`
	ClientID      string `json:"client_id,omitempty"`
	ClientSecret  string `json:"client_secret,omitempty"`
	plugin.ExtraContainer
}

IntrospectParams defines input parameters for token introspection (RFC 7662).

type IntrospectResult

type IntrospectResult struct {
	Active    bool           `json:"active"`
	Scope     string         `json:"scope,omitempty"`
	ClientID  string         `json:"client_id,omitempty"`
	Username  string         `json:"username,omitempty"`
	TokenType string         `json:"token_type,omitempty"`
	Exp       int64          `json:"exp,omitempty"`
	Iat       int64          `json:"iat,omitempty"`
	Nbf       int64          `json:"nbf,omitempty"`
	Sub       string         `json:"sub,omitempty"`
	Aud       []string       `json:"aud,omitempty"`
	Iss       string         `json:"iss,omitempty"`
	Jti       string         `json:"jti,omitempty"`
	Extra     map[string]any `json:"extra,omitempty"`
}

IntrospectResult represents the introspection metadata (RFC 7662).

type JWTSigner

type JWTSigner interface {
	// Sign signs the given claims map with the configured algorithm and lifetime.
	Sign(ctx context.Context, claims map[string]any, expiresIn time.Duration) (tokenString string, keyID string, err error)

	// Verify validates the JWT signature, integrity, and expiration, returning verified claims.
	Verify(ctx context.Context, tokenString string) (claims map[string]any, err error)
}

JWTSigner defines the contract for signing and verifying JWT tokens (ID Tokens and RFC 9068 Access Tokens).

type ListConsentsParams

type ListConsentsParams struct {
	UserID string `json:"user_id"`
	plugin.ExtraContainer
}

ListConsentsParams defines input parameters to list user consents.

type ListConsentsResult

type ListConsentsResult struct {
	Consents []*OAuthConsent `json:"consents"`
}

ListConsentsResult contains the list of active user consents.

type OAuthAccessToken

type OAuthAccessToken struct {
	// ID is the internal unique identifier of the access token record.
	ID string `json:"id"`

	// Token is the SHA-256 hash or encrypted representation of the access token string.
	Token string `json:"token"`

	// ClientID is the client application that received this token.
	ClientID string `json:"client_id"`

	// UserID is the authenticated user ID (nil for machine-to-machine client credentials).
	UserID *string `json:"user_id,omitempty"`

	// SessionID is the optional session ID tied to this token.
	SessionID *string `json:"session_id,omitempty"`

	// RefreshID is the optional ID of the parent refresh token that spawned this access token.
	RefreshID *string `json:"refresh_id,omitempty"`

	// ReferenceID is an optional external identifier.
	ReferenceID *string `json:"reference_id,omitempty"`

	// Scopes is the list of granted scopes authorized by this token.
	Scopes []string `json:"scopes"`

	// ExpiresAt is the timestamp when the access token expires.
	ExpiresAt time.Time `json:"expires_at"`

	// CreatedAt is the timestamp when the access token was issued.
	CreatedAt time.Time `json:"created_at"`
}

OAuthAccessToken represents an issued access token (stored for opaque tokens or introspection).

type OAuthAuthorizationCode

type OAuthAuthorizationCode struct {
	// ID is the internal unique identifier of the authorization code record.
	ID string `json:"id"`

	// Code is the raw or hashed authorization code string.
	Code string `json:"code"`

	// ClientID is the client application that requested the authorization code.
	ClientID string `json:"client_id"`

	// UserID is the authenticated user ID granting authorization.
	UserID string `json:"user_id"`

	// SessionID is the active user session ID at the time of authorization.
	SessionID string `json:"session_id"`

	// RedirectURI is the redirect URI verified and locked during the authorization step.
	RedirectURI string `json:"redirect_uri"`

	// CodeChallenge is the Base64URL-encoded SHA-256 PKCE challenge (RFC 7636).
	CodeChallenge string `json:"code_challenge"`

	// CodeChallengeMethod is the PKCE transform method (always "S256" in OAuth 2.1).
	CodeChallengeMethod string `json:"code_challenge_method"`

	// Scopes is the list of granted scopes associated with this authorization code.
	Scopes []string `json:"scopes"`

	// Nonce is an optional string value used to associate a client session with an ID Token (OIDC).
	Nonce string `json:"nonce,omitempty"`

	// Resource is an optional target resource indicator (RFC 8707).
	Resource string `json:"resource,omitempty"`

	// ExpiresAt is the timestamp after which this authorization code is invalid (default: 10m).
	ExpiresAt time.Time `json:"expires_at"`

	// CreatedAt is the timestamp when the authorization code was issued.
	CreatedAt time.Time `json:"created_at"`
}

OAuthAuthorizationCode represents a single-use authorization code issued during the authorization code flow.

type OAuthClient

type OAuthClient struct {
	// ID is the internal unique identifier of the client record in the database.
	ID string `json:"id"`

	// ClientID is the unique public client identifier used in OAuth requests.
	ClientID string `json:"client_id"`

	// ClientSecret is the hashed or encrypted client secret (nil for public clients).
	ClientSecret *string `json:"client_secret,omitempty"`

	// ClientSecretExpiresAt is the expiration timestamp for the client secret, if applicable.
	ClientSecretExpiresAt *time.Time `json:"client_secret_expires_at,omitempty"`

	// Name is the human-readable display name of the client application.
	Name string `json:"name"`

	// URI is the home page URL of the client application.
	URI string `json:"uri,omitempty"`

	// Icon is the URL of the client application logo or icon.
	Icon string `json:"icon,omitempty"`

	// Contacts is a list of contact email addresses for the client application.
	Contacts []string `json:"contacts,omitempty"`

	// TOS is the Terms of Service URL for the client application.
	TOS string `json:"tos,omitempty"`

	// Policy is the Privacy Policy URL for the client application.
	Policy string `json:"policy,omitempty"`

	// SoftwareID is an identifier assigned by the client developer (RFC 7591).
	SoftwareID string `json:"software_id,omitempty"`

	// SoftwareVersion is a version identifier assigned by the client developer (RFC 7591).
	SoftwareVersion string `json:"software_version,omitempty"`

	// SoftwareStatement is a signed software statement JWT (RFC 7591).
	SoftwareStatement string `json:"software_statement,omitempty"`

	// RedirectURIs is the list of authorized callback redirect URIs for this client.
	RedirectURIs []string `json:"redirect_uris"`

	// PostLogoutRedirectURIs is the list of allowed post-logout redirect URIs (RP-Initiated Logout).
	PostLogoutRedirectURIs []string `json:"post_logout_redirect_uris,omitempty"`

	// TokenEndpointAuthMethod specifies the authentication method used at the token endpoint ("client_secret_basic", "client_secret_post", "none").
	TokenEndpointAuthMethod TokenEndpointAuthMethod `json:"token_endpoint_auth_method"`

	// GrantTypes is the list of OAuth 2.1 grant types allowed for this client ("authorization_code", "client_credentials", "refresh_token").
	GrantTypes []GrantType `json:"grant_types"`

	// ResponseTypes is the list of response types allowed for this client (typically ["code"]).
	ResponseTypes []ResponseType `json:"response_types"`

	// Scopes is the list of authorized scopes the client may request.
	Scopes []string `json:"scopes,omitempty"`

	// Public indicates if the client is a public client (e.g. SPA, mobile) incapable of protecting secrets.
	Public bool `json:"public"`

	// Type specifies the client category (e.g., "confidential", "public").
	Type ClientType `json:"type,omitempty"`

	// RequirePKCE enforces PKCE code challenge verification (defaults to true in OAuth 2.1).
	RequirePKCE bool `json:"require_pkce"`

	// SubjectType specifies the subject identifier type for OIDC ("public" or "pairwise").
	SubjectType SubjectType `json:"subject_type,omitempty"`

	// SkipConsent indicates if the user consent prompt can be bypassed for trusted first-party clients.
	SkipConsent bool `json:"skip_consent"`

	// EnableEndSession allows this client to trigger RP-Initiated Logout (OIDC End Session).
	EnableEndSession bool `json:"enable_end_session"`

	// Disabled indicates if the client has been administratively disabled.
	Disabled bool `json:"disabled"`

	// UserID is the optional ID of the user who registered/owns this client.
	UserID *string `json:"user_id,omitempty"`

	// ReferenceID is an optional external identifier for multi-tenant or organization mapping.
	ReferenceID *string `json:"reference_id,omitempty"`

	// Metadata holds arbitrary custom properties and client configuration.
	Metadata map[string]any `json:"metadata,omitempty"`

	// CreatedAt is the timestamp when the client record was created.
	CreatedAt time.Time `json:"created_at"`

	// UpdatedAt is the timestamp when the client record was last updated.
	UpdatedAt time.Time `json:"updated_at"`
}

OAuthClient represents a registered OAuth 2.1 / OpenID Connect client application.

type OAuthConsent

type OAuthConsent struct {
	// ID is the internal unique identifier of the consent record.
	ID string `json:"id"`

	// ClientID is the client application identifier.
	ClientID string `json:"client_id"`

	// UserID is the user ID who granted the consent.
	UserID string `json:"user_id"`

	// ReferenceID is an optional external identifier.
	ReferenceID *string `json:"reference_id,omitempty"`

	// Scopes is the list of scopes approved by the user.
	Scopes []string `json:"scopes"`

	// CreatedAt is the timestamp when consent was first granted.
	CreatedAt time.Time `json:"created_at"`

	// UpdatedAt is the timestamp when consent was last modified.
	UpdatedAt time.Time `json:"updated_at"`
}

OAuthConsent represents explicit consent granted by an end-user to a client application for a set of scopes.

type OAuthMetadataParams

type OAuthMetadataParams struct {
	plugin.ExtraContainer
}

OAuthMetadataParams defines input parameters for RFC 8414 metadata.

type OAuthMetadataResult

type OAuthMetadataResult struct {
	Issuer                            string   `json:"issuer"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint"`
	IntrospectionEndpoint             string   `json:"introspection_endpoint"`
	RevocationEndpoint                string   `json:"revocation_endpoint"`
	RegistrationEndpoint              string   `json:"registration_endpoint,omitempty"`
	ResponseTypesSupported            []string `json:"response_types_supported"`
	GrantTypesSupported               []string `json:"grant_types_supported"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported"`
	TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
	ScopesSupported                   []string `json:"scopes_supported"`
}

OAuthMetadataResult represents Authorization Server Metadata (RFC 8414).

type OAuthRefreshToken

type OAuthRefreshToken struct {
	// ID is the internal unique identifier of the refresh token record.
	ID string `json:"id"`

	// Token is the SHA-256 hash or encrypted refresh token string.
	Token string `json:"token"`

	// ClientID is the client application holding this refresh token.
	ClientID string `json:"client_id"`

	// UserID is the user ID associated with the issued refresh token.
	UserID string `json:"user_id"`

	// SessionID is the optional session ID tied to the refresh token.
	SessionID *string `json:"session_id,omitempty"`

	// ReferenceID is an optional external identifier.
	ReferenceID *string `json:"reference_id,omitempty"`

	// FamilyID is a unique identifier linking all rotated refresh tokens in the same token family.
	// If a revoked token in this family is reused, the entire family is revoked (RFC 6749 Section 10.4).
	FamilyID string `json:"family_id"`

	// Scopes is the list of granted scopes bound to this refresh token.
	Scopes []string `json:"scopes"`

	// ExpiresAt is the timestamp when the refresh token expires.
	ExpiresAt time.Time `json:"expires_at"`

	// CreatedAt is the timestamp when the refresh token was issued.
	CreatedAt time.Time `json:"created_at"`

	// RevokedAt is the timestamp when the refresh token was revoked, if applicable.
	RevokedAt *time.Time `json:"revoked_at,omitempty"`

	// AuthTime is the timestamp when the user originally performed authentication.
	AuthTime *time.Time `json:"auth_time,omitempty"`
}

OAuthRefreshToken represents a persisted refresh token with rotation and family tracking.

type OpenIDConfigurationParams

type OpenIDConfigurationParams struct {
	plugin.ExtraContainer
}

OpenIDConfigurationParams defines input parameters for OpenID Provider metadata.

type OpenIDConfigurationResult

type OpenIDConfigurationResult struct {
	Issuer                            string   `json:"issuer"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint"`
	UserinfoEndpoint                  string   `json:"userinfo_endpoint"`
	IntrospectionEndpoint             string   `json:"introspection_endpoint"`
	RevocationEndpoint                string   `json:"revocation_endpoint"`
	EndSessionEndpoint                string   `json:"end_session_endpoint,omitempty"`
	RegistrationEndpoint              string   `json:"registration_endpoint,omitempty"`
	JwksURI                           string   `json:"jwks_uri,omitempty"`
	ResponseTypesSupported            []string `json:"response_types_supported"`
	SubjectTypesSupported             []string `json:"subject_types_supported"`
	IDTokenSigningAlgValuesSupported  []string `json:"id_token_signing_alg_values_supported"`
	ScopesSupported                   []string `json:"scopes_supported"`
	TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
	ClaimsSupported                   []string `json:"claims_supported"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported"`
	GrantTypesSupported               []string `json:"grant_types_supported"`
}

OpenIDConfigurationResult represents discovery metadata (OpenID Connect Discovery 1.0).

type Option

type Option func(*Config)

Option configures the OAuth 2.1 Provider plugin.

func WithAccessTokenType

func WithAccessTokenType(t AccessTokenType) Option

WithAccessTokenType sets the Access Token format ("jwt" or "opaque").

func WithCustomAccessTokenClaims

func WithCustomAccessTokenClaims(fn CustomClaimsFunc) Option

WithCustomAccessTokenClaims sets a custom claims injector for JWT Access Tokens.

func WithCustomIDTokenClaims

func WithCustomIDTokenClaims(fn CustomClaimsFunc) Option

WithCustomIDTokenClaims sets a custom claims injector for OIDC ID Tokens.

func WithCustomUserInfoClaims

func WithCustomUserInfoClaims(fn CustomClaimsFunc) Option

WithCustomUserInfoClaims sets a custom claims injector for the UserInfo endpoint.

func WithDynamicClientRegistration

func WithDynamicClientRegistration(allow, allowUnauthenticated bool) Option

WithDynamicClientRegistration configures RFC 7591 Dynamic Client Registration.

func WithGrantTypes

func WithGrantTypes(types ...GrantType) Option

WithGrantTypes overrides the list of enabled grant types.

func WithIssuer

func WithIssuer(issuer string) Option

WithIssuer configures the authorization server issuer URL.

func WithJWTSigner

func WithJWTSigner(signer JWTSigner) Option

WithJWTSigner configures a custom JWT signer (such as an adapter for plugins/jwt or RSA/ECDSA signer).

func WithPages

func WithPages(loginPage, consentPage string) Option

WithPages configures the interactive login and consent page redirect URLs.

func WithPairwiseSecret

func WithPairwiseSecret(secret string) Option

WithPairwiseSecret sets the secret key for deriving pairwise pseudonymous subject identifiers.

func WithScopes

func WithScopes(scopes ...string) Option

WithScopes overrides the list of supported OAuth/OIDC scopes.

func WithStoreModes

func WithStoreModes(secretMode, tokenMode StoreMode, secretKey string) Option

WithStoreModes configures the storage strategy for secrets and tokens.

func WithTokenExpirations

func WithTokenExpirations(code, access, refresh, idToken time.Duration) Option

WithTokenExpirations configures expiration lifetimes for all token types.

type Plugin

type Plugin struct {
	// contains filtered or unexported fields
}

Plugin implements plugin.Plugin for the OAuth 2.1 & OpenID Connect Provider.

func New

func New(repo Repository, opts ...Option) *Plugin

New creates a new OAuth 2.1 Provider plugin with the given repository and options.

func (*Plugin) Authorize

func (p *Plugin) Authorize(ctx context.Context, params AuthorizeParams) (*AuthorizeResult, error)

Authorize handles the authorization step of the OAuth 2.1 Authorization Code Flow.

func (*Plugin) Config

func (p *Plugin) Config() Config

Config returns the current configuration of the plugin.

func (*Plugin) Consent

func (p *Plugin) Consent(ctx context.Context, params ConsentParams) (*ConsentResult, error)

Consent processes the end-user's decision to grant or deny requested scopes.

func (*Plugin) ContinueAuthorize

func (p *Plugin) ContinueAuthorize(ctx context.Context, params ContinueAuthorizeParams) (*AuthorizeResult, error)

ContinueAuthorize resumes the authorization code issuance after a user authenticates or consents.

func (*Plugin) DeleteClient

func (p *Plugin) DeleteClient(ctx context.Context, params DeleteClientParams) (*DeleteClientResult, error)

DeleteClient removes an OAuth client record from storage.

func (*Plugin) EndSession

func (p *Plugin) EndSession(ctx context.Context, params EndSessionParams) (*EndSessionResult, error)

EndSession implements OpenID Connect RP-Initiated Logout 1.0.

func (*Plugin) GetClient

func (p *Plugin) GetClient(ctx context.Context, params GetClientParams) (*GetClientResult, error)

GetClient retrieves an OAuth client by its ClientID.

func (*Plugin) GetOAuthAuthorizationServerMetadata

func (p *Plugin) GetOAuthAuthorizationServerMetadata(ctx context.Context, params OAuthMetadataParams) (*OAuthMetadataResult, error)

GetOAuthAuthorizationServerMetadata returns OAuth 2.0 Authorization Server Metadata per RFC 8414.

func (*Plugin) GetOpenIDConfiguration

func (p *Plugin) GetOpenIDConfiguration(ctx context.Context, params OpenIDConfigurationParams) (*OpenIDConfigurationResult, error)

GetOpenIDConfiguration returns the OpenID Connect Discovery 1.0 metadata document.

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the unique identifier for the OAuth 2.1 plugin.

func (*Plugin) Init

func (p *Plugin) Init(ctx *plugin.Context) error

Init initializes the plugin within the shared plugin.Context environment.

func (*Plugin) Introspect

func (p *Plugin) Introspect(ctx context.Context, params IntrospectParams) (*IntrospectResult, error)

Introspect inspects an active access token or refresh token according to RFC 7662.

func (*Plugin) ListConsents

func (p *Plugin) ListConsents(ctx context.Context, params ListConsentsParams) (*ListConsentsResult, error)

ListConsents retrieves all active consents granted by a specific user.

func (*Plugin) RegisterClient

func (p *Plugin) RegisterClient(ctx context.Context, params RegisterClientParams) (*RegisterClientResult, error)

RegisterClient performs RFC 7591 Dynamic Client Registration or programmatic client creation.

func (*Plugin) Repository

func (p *Plugin) Repository() Repository

Repository returns the underlying storage repository.

func (*Plugin) RequireScope added in v0.20.0

func (p *Plugin) RequireScope(requiredScopes ...string) func(next http.Handler) http.Handler

RequireScope returns a net/http middleware handler verifying valid OAuth2 Access Token and required scopes.

func (*Plugin) Revoke

func (p *Plugin) Revoke(ctx context.Context, params RevokeParams) (*RevokeResult, error)

Revoke revokes an access token or refresh token according to RFC 7009.

func (*Plugin) RevokeConsent

func (p *Plugin) RevokeConsent(ctx context.Context, params RevokeConsentParams) (*RevokeConsentResult, error)

RevokeConsent revokes all scopes previously granted by a user to a specific OAuth client.

func (*Plugin) RotateClientSecret

func (p *Plugin) RotateClientSecret(ctx context.Context, params RotateClientSecretParams) (*RotateClientSecretResult, error)

RotateClientSecret generates and replaces the client secret for a confidential OAuth client.

func (*Plugin) Token

func (p *Plugin) Token(ctx context.Context, params TokenParams) (*TokenResult, error)

Token handles token exchanges across all supported OAuth 2.1 grant types: "authorization_code", "refresh_token", and "client_credentials".

func (*Plugin) UpdateClient

func (p *Plugin) UpdateClient(ctx context.Context, params UpdateClientParams) (*UpdateClientResult, error)

UpdateClient updates mutable properties of an existing OAuth client.

func (*Plugin) UserInfo

func (p *Plugin) UserInfo(ctx context.Context, params UserInfoParams) (*UserInfoResult, error)

UserInfo resolves the claims of the authenticated user for the given access token (OIDC Core 1.0).

type RegisterClientParams

type RegisterClientParams struct {
	ClientName              string                  `json:"client_name"`
	ClientURI               string                  `json:"client_uri,omitempty"`
	LogoURI                 string                  `json:"logo_uri,omitempty"`
	Contacts                []string                `json:"contacts,omitempty"`
	TOSURI                  string                  `json:"tos_uri,omitempty"`
	PolicyURI               string                  `json:"policy_uri,omitempty"`
	SoftwareID              string                  `json:"software_id,omitempty"`
	SoftwareVersion         string                  `json:"software_version,omitempty"`
	RedirectURIs            []string                `json:"redirect_uris"`
	PostLogoutRedirectURIs  []string                `json:"post_logout_redirect_uris,omitempty"`
	TokenEndpointAuthMethod TokenEndpointAuthMethod `json:"token_endpoint_auth_method,omitempty"`
	GrantTypes              []GrantType             `json:"grant_types,omitempty"`
	ResponseTypes           []ResponseType          `json:"response_types,omitempty"`
	Scope                   string                  `json:"scope,omitempty"`
	Public                  bool                    `json:"public,omitempty"`
	SubjectType             SubjectType             `json:"subject_type,omitempty"`
	SkipConsent             bool                    `json:"skip_consent,omitempty"`
	EnableEndSession        bool                    `json:"enable_end_session,omitempty"`
	UserID                  *string                 `json:"user_id,omitempty"`
	Metadata                map[string]any          `json:"metadata,omitempty"`
	plugin.ExtraContainer
}

RegisterClientParams defines input parameters for Dynamic Client Registration (RFC 7591).

type RegisterClientResult

type RegisterClientResult struct {
	Client       *OAuthClient `json:"client"`
	ClientID     string       `json:"client_id"`
	ClientSecret string       `json:"client_secret,omitempty"`
}

RegisterClientResult contains the registered client entity and generated secrets.

type Repository

type Repository interface {
	// FindClientByClientID retrieves an OAuth client by its public ClientID string.
	//
	// Function:
	//   Called during authorize, token exchange, client auth, and introspection endpoints.
	//
	// Storage:
	//   Both (Cache-Aside Strategy) - Cached by client_id in Redis/memory.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - clientID: Public client_id string.
	//
	// Returns:
	//   - *OAuthClient: Matching client entity if found.
	//   - error: ErrClientNotFound if missing, or database error.
	//
	// Example SQL:
	//   SELECT id, client_id, client_secret, name, redirect_uris, grant_types, created_at, updated_at FROM oauth_clients WHERE client_id = $1 LIMIT 1;
	//
	// Example Cache (Redis):
	//   val, err := rdb.Get(ctx, "oauth:client:" + clientID).Bytes()
	FindClientByClientID(ctx context.Context, clientID string) (*OAuthClient, error)

	// FindClientByID retrieves an OAuth client by its primary database record ID.
	//
	// Function:
	//   Used in administrative client management panels.
	//
	// Storage:
	//   Database (GORM / SQL) - Client primary key lookup.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - id: Primary key record ID.
	//
	// Returns:
	//   - *OAuthClient: Matching client entity.
	//   - error: ErrClientNotFound if missing.
	//
	// Example SQL:
	//   SELECT id, client_id, client_secret, name, redirect_uris, grant_types, created_at, updated_at FROM oauth_clients WHERE id = $1 LIMIT 1;
	FindClientByID(ctx context.Context, id string) (*OAuthClient, error)

	// ListClientsByUserID retrieves all OAuth clients owned/registered by a specific user.
	//
	// Function:
	//   Used in user settings UI to display user-created OAuth applications.
	//
	// Storage:
	//   Database (GORM / SQL) - Relational list query.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - userID: Target user ID.
	//
	// Returns:
	//   - []*OAuthClient: Slice of client entities.
	//   - error: Nil on success.
	//
	// Example SQL:
	//   SELECT id, client_id, client_secret, name, redirect_uris, grant_types, created_at, updated_at FROM oauth_clients WHERE user_id = $1;
	ListClientsByUserID(ctx context.Context, userID string) ([]*OAuthClient, error)

	// CreateClient persists a newly registered OAuth client.
	//
	// Function:
	//   Called during dynamic client registration or administrative application onboarding.
	//
	// Storage:
	//   Database (GORM / SQL) - Relational insert.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - client: OAuthClient entity to persist.
	//
	// Returns:
	//   - error: Nil on success, or database error.
	//
	// Example SQL:
	//   INSERT INTO oauth_clients (id, client_id, client_secret, name, redirect_uris, grant_types, created_at, updated_at)
	//   VALUES ($1, $2, $3, $4, $5, $6, $7, $8);
	CreateClient(ctx context.Context, client *OAuthClient) error

	// UpdateClient updates mutable fields of an existing OAuth client.
	//
	// Function:
	//   Called when updating client settings, redirect URIs, or secret keys.
	//
	// Storage:
	//   Database (GORM / SQL) - Relational update.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - client: Modified OAuthClient entity.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   UPDATE oauth_clients SET name = $1, redirect_uris = $2, grant_types = $3, updated_at = $4 WHERE client_id = $5;
	UpdateClient(ctx context.Context, client *OAuthClient) error

	// DeleteClient removes an OAuth client record from storage by its client_id.
	//
	// Function:
	//   Called when unregistering an OAuth application.
	//
	// Storage:
	//   Database (GORM / SQL) - Record deletion.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - clientID: Public client ID string.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   DELETE FROM oauth_clients WHERE client_id = $1;
	DeleteClient(ctx context.Context, clientID string) error

	// CreateAuthorizationCode persists a single-use authorization code record.
	//
	// Function:
	//   Called at the completion of the interactive authorization code flow.
	//
	// Storage:
	//   Cache (Redis / In-Memory TTL) - Short-lived authorization code state.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - code: OAuthAuthorizationCode entity containing code secret, PKCE challenge, and scopes.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   INSERT INTO oauth_codes (id, code, client_id, user_id, redirect_uri, scope, code_challenge, code_challenge_method, expires_at, created_at)
	//   VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
	//
	// Example Cache (Redis):
	//   err := rdb.Set(ctx, "oauth:code:" + code.Code, bytes, ttl).Err()
	CreateAuthorizationCode(ctx context.Context, code *OAuthAuthorizationCode) error

	// ConsumeAuthorizationCode atomically finds and removes (or marks consumed) an authorization code in a single step.
	// This atomic operation guarantees anti-replay protection and race condition prevention.
	//
	// Function:
	//   Called during authorization_code token exchange.
	//
	// Storage:
	//   Cache (Redis GETDEL / Memory) - Atomic read-and-delete single-use code consumption.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - code: Raw code secret string.
	//
	// Returns:
	//   - *OAuthAuthorizationCode: Consumed authorization code record.
	//   - error: ErrInvalidAuthorizationCode if missing or expired.
	//
	// Example SQL:
	//   DELETE FROM oauth_codes WHERE code = $1 AND expires_at > $2 RETURNING id, code, client_id, user_id, redirect_uri, scope, code_challenge, code_challenge_method, expires_at, created_at;
	//
	// Example Cache (Redis):
	//   val, err := rdb.GetDel(ctx, "oauth:code:" + code).Bytes()
	ConsumeAuthorizationCode(ctx context.Context, code string) (*OAuthAuthorizationCode, error)

	// CreateAccessToken persists an issued access token.
	//
	// Function:
	//   Called during token generation in token endpoints.
	//
	// Storage:
	//   Database (GORM / SQL) - Token persistence.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - token: OAuthAccessToken entity containing hashed token, client ID, user ID, scopes, and expiry.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   INSERT INTO oauth_access_tokens (id, token_hash, client_id, user_id, scope, expires_at, created_at)
	//   VALUES ($1, $2, $3, $4, $5, $6, $7);
	CreateAccessToken(ctx context.Context, token *OAuthAccessToken) error

	// FindAccessToken retrieves an access token record by its token hash.
	//
	// Function:
	//   Called during RFC 7662 Introspection or API bearer authorization validation.
	//
	// Storage:
	//   Both (Cache-Aside Strategy) - Cached in Redis (`oauth:token:<tokenHash>`) for fast token validation.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - tokenHash: SHA-256 hash of the bearer token string.
	//
	// Returns:
	//   - *OAuthAccessToken: Matching token record if found.
	//   - error: ErrInvalidAccessToken if missing or expired.
	//
	// Example SQL:
	//   SELECT id, token_hash, client_id, user_id, scope, expires_at, created_at FROM oauth_access_tokens WHERE token_hash = $1 LIMIT 1;
	//
	// Example Cache (Redis):
	//   val, err := rdb.Get(ctx, "oauth:token:" + tokenHash).Bytes()
	FindAccessToken(ctx context.Context, tokenHash string) (*OAuthAccessToken, error)

	// DeleteAccessToken removes an access token from storage upon revocation or expiration.
	//
	// Function:
	//   Called during RFC 7009 token revocation.
	//
	// Storage:
	//   Database (GORM / SQL) - Token revocation deletion.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - tokenHash: Token hash.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   DELETE FROM oauth_access_tokens WHERE token_hash = $1;
	DeleteAccessToken(ctx context.Context, tokenHash string) error

	// CreateRefreshToken persists an issued refresh token with its family ID.
	//
	// Function:
	//   Called during token issuance for offline_access grants.
	//
	// Storage:
	//   Database (GORM / SQL) - Refresh token record insertion.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - token: OAuthRefreshToken entity containing token hash, family ID, and revocation state.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   INSERT INTO oauth_refresh_tokens (id, token_hash, family_id, client_id, user_id, scope, revoked, expires_at, created_at)
	//   VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9);
	CreateRefreshToken(ctx context.Context, token *OAuthRefreshToken) error

	// FindRefreshToken retrieves a refresh token record by its token hash.
	//
	// Function:
	//   Called during refresh_token grant type token renewal.
	//
	// Storage:
	//   Database (GORM / SQL) - Refresh token query.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - tokenHash: SHA-256 hash of the refresh token.
	//
	// Returns:
	//   - *OAuthRefreshToken: Refresh token entity if valid.
	//   - error: ErrInvalidRefreshToken if missing or expired, ErrRefreshTokenRevoked if revoked.
	//
	// Example SQL:
	//   SELECT id, token_hash, family_id, client_id, user_id, scope, revoked, expires_at, created_at FROM oauth_refresh_tokens WHERE token_hash = $1 LIMIT 1;
	FindRefreshToken(ctx context.Context, tokenHash string) (*OAuthRefreshToken, error)

	// DeleteRefreshToken removes a single refresh token from storage.
	//
	// Function:
	//   Called when consuming a refresh token during rotation.
	//
	// Storage:
	//   Database (GORM / SQL) - Single refresh token deletion.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - tokenHash: Token hash.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   DELETE FROM oauth_refresh_tokens WHERE token_hash = $1;
	DeleteRefreshToken(ctx context.Context, tokenHash string) error

	// RevokeRefreshTokenFamily invalidates all refresh tokens and associated access tokens in a token family.
	//
	// Function:
	//   Called when refresh token reuse is detected (detecting token theft attack).
	//
	// Storage:
	//   Database (GORM / SQL) - Token family revocation update.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - familyID: Token family identifier string.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   UPDATE oauth_refresh_tokens SET revoked = true WHERE family_id = $1;
	RevokeRefreshTokenFamily(ctx context.Context, familyID string) error

	// FindConsent retrieves user consent granted to a client application.
	//
	// Function:
	//   Used during authorize request to check if user has previously approved scopes.
	//
	// Storage:
	//   Database (GORM / SQL) - Consent record query.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - clientID: Target client ID.
	//   - userID: Target user ID.
	//
	// Returns:
	//   - *OAuthConsent: Matching consent entity if found.
	//   - error: ErrConsentRequired if not consented.
	//
	// Example SQL:
	//   SELECT id, client_id, user_id, scopes, created_at, updated_at FROM oauth_consents WHERE client_id = $1 AND user_id = $2 LIMIT 1;
	FindConsent(ctx context.Context, clientID, userID string) (*OAuthConsent, error)

	// ListConsentsByUserID retrieves all active consents granted by a specific user.
	//
	// Function:
	//   Used in user security settings panel to show connected applications.
	//
	// Storage:
	//   Database (GORM / SQL) - User consents list query.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - userID: Target user ID.
	//
	// Returns:
	//   - []*OAuthConsent: Slice of consents.
	//   - error: Nil on success.
	//
	// Example SQL:
	//   SELECT id, client_id, user_id, scopes, created_at, updated_at FROM oauth_consents WHERE user_id = $1;
	ListConsentsByUserID(ctx context.Context, userID string) ([]*OAuthConsent, error)

	// CreateConsent records a newly granted user consent.
	//
	// Function:
	//   Called after user approves authorization prompt.
	//
	// Storage:
	//   Database (GORM / SQL) - Consent entity creation.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - consent: OAuthConsent entity.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   INSERT INTO oauth_consents (id, client_id, user_id, scopes, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6);
	CreateConsent(ctx context.Context, consent *OAuthConsent) error

	// UpdateConsent updates the granted scopes of an existing consent.
	//
	// Function:
	//   Called when user grants additional scopes to an already authorized app.
	//
	// Storage:
	//   Database (GORM / SQL) - Consent scopes update.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - consent: Modified OAuthConsent entity.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   UPDATE oauth_consents SET scopes = $1, updated_at = $2 WHERE id = $3;
	UpdateConsent(ctx context.Context, consent *OAuthConsent) error

	// DeleteConsent revokes and removes a user consent record.
	//
	// Function:
	//   Called when a user disconnects an authorized application.
	//
	// Storage:
	//   Database (GORM / SQL) - Consent deletion.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - id: Primary key record ID.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   DELETE FROM oauth_consents WHERE id = $1;
	DeleteConsent(ctx context.Context, id string) error

	// FindUserByID retrieves a user domain entity by user ID.
	//
	// Function:
	//   Used during UserInfo endpoint processing or authorization prompt rendering.
	//
	// Storage:
	//   Database (GORM / SQL) - User entity lookup.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - userID: Target user ID.
	//
	// Returns:
	//   - *entity.User: Matching user entity if found.
	//   - error: ErrInvalidClient/ErrUserNotFound if missing.
	//
	// Example SQL:
	//   SELECT id, email, name, email_verified, created_at, updated_at FROM users WHERE id = $1 LIMIT 1;
	FindUserByID(ctx context.Context, userID string) (*entity.User, error)

	// FindSessionByID retrieves an active session domain entity by session ID.
	//
	// Function:
	//   Used during authorize prompt check or RP-Initiated Logout.
	//
	// Storage:
	//   Both (Cache-Aside Strategy) - Session retrieval by ID.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - sessionID: Session identifier.
	//
	// Returns:
	//   - *entity.Session: Active session entity if found.
	//   - error: ErrLoginRequired if missing or expired.
	//
	// Example SQL:
	//   SELECT id, user_id, token, expires_at, created_at, updated_at FROM sessions WHERE id = $1 LIMIT 1;
	//
	// Example Cache (Redis):
	//   val, err := rdb.Get(ctx, "session:" + sessionID).Bytes()
	FindSessionByID(ctx context.Context, sessionID string) (*entity.Session, error)

	// DeleteSessionByID deletes a session upon RP-Initiated Logout.
	//
	// Function:
	//   Called during OpenID Connect end-session logout endpoint.
	//
	// Storage:
	//   Database (GORM / SQL) - Session deletion.
	//
	// Arguments:
	//   - ctx: Request cancellation context.
	//   - sessionID: Session identifier.
	//
	// Returns:
	//   - error: Nil on success.
	//
	// Example SQL:
	//   DELETE FROM sessions WHERE id = $1;
	DeleteSessionByID(ctx context.Context, sessionID string) error
}

Repository defines the storage contract required by the OAuth 2.1 Provider plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, SQLite, MongoDB, GORM).

Implementation Example (GORM / database/sql):

type GormOAuth2Repository struct {
	db *gorm.DB
}

func (r *GormOAuth2Repository) FindClientByClientID(ctx context.Context, clientID string) (*oauth2.OAuthClient, error) {
	var c oauth2.OAuthClient
	if err := r.db.WithContext(ctx).Where("client_id = ?", clientID).First(&c).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, oauth2.ErrClientNotFound
		}
		return nil, err
	}
	return &c, nil
}

Storage and Caching Recommendation (Token Introspection & Authorization Code Cache):

Access Tokens and Authorization Codes can be cached in Redis to achieve high-throughput introspection:

  1. Authorization Codes (`ConsumeAuthorizationCode`): Store ephemeral codes in Redis (`oauth:code:<code>`) with short TTL. Use `GETDEL` for single-use consumption.

  2. Access Token Introspection (`FindAccessToken`): Cache active token hashes in Redis (`oauth:token:<hash>`) with TTL equal to token remaining lifetime.

Recommended Caching Decorator Example:

type CachedOAuth2Repository struct {
	dbRepo oauth2.Repository
	redis  *redis.Client
}

func (r *CachedOAuth2Repository) FindAccessToken(ctx context.Context, tokenHash string) (*oauth2.OAuthAccessToken, error) {
	val, err := r.redis.Get(ctx, "oauth:token:"+tokenHash).Bytes()
	if err == nil {
		var token oauth2.OAuthAccessToken
		if json.Unmarshal(val, &token) == nil {
			return &token, nil // Fast Introspection Cache Hit
		}
	}
	token, err := r.dbRepo.FindAccessToken(ctx, tokenHash)
	if err == nil {
		bytes, _ := json.Marshal(token)
		ttl := time.Until(token.ExpiresAt)
		r.redis.Set(ctx, "oauth:token:"+tokenHash, bytes, ttl)
	}
	return token, err
}

type ResponseType

type ResponseType string

ResponseType represents the authorization endpoint response type.

const (
	// ResponseTypeCode represents the authorization code response type ("code").
	ResponseTypeCode ResponseType = "code"
)

type RevokeConsentParams

type RevokeConsentParams struct {
	ClientID string `json:"client_id"`
	UserID   string `json:"user_id"`
	plugin.ExtraContainer
}

RevokeConsentParams defines input parameters to revoke user consent for a client.

type RevokeConsentResult

type RevokeConsentResult struct {
	Success bool `json:"success"`
}

RevokeConsentResult reports the outcome of revoking consent.

type RevokeParams

type RevokeParams struct {
	Token         string `json:"token"`
	TokenTypeHint string `json:"token_type_hint,omitempty"`
	ClientID      string `json:"client_id,omitempty"`
	ClientSecret  string `json:"client_secret,omitempty"`
	plugin.ExtraContainer
}

RevokeParams defines input parameters for token revocation (RFC 7009).

type RevokeResult

type RevokeResult struct {
	Success bool `json:"success"`
}

RevokeResult reports the result of token revocation.

type RotateClientSecretParams

type RotateClientSecretParams struct {
	ClientID string `json:"client_id"`
	plugin.ExtraContainer
}

RotateClientSecretParams defines input parameters to rotate a client secret.

type RotateClientSecretResult

type RotateClientSecretResult struct {
	ClientID        string `json:"client_id"`
	NewClientSecret string `json:"new_client_secret"`
}

RotateClientSecretResult contains the new raw client secret.

type SessionEndedEventPayload

type SessionEndedEventPayload struct {
	// UserID is the user ID whose session ended.
	UserID string `json:"user_id"`

	// ClientID is the client that initiated the logout, if known.
	ClientID string `json:"client_id,omitempty"`

	// PostLogoutRedirectURI is the redirect destination after logout.
	PostLogoutRedirectURI string `json:"post_logout_redirect_uri,omitempty"`

	// Timestamp is the moment the session ended.
	Timestamp time.Time `json:"timestamp"`
}

SessionEndedEventPayload represents the payload dispatched when RP-Initiated Logout completes.

type StoreMode

type StoreMode string

StoreMode defines how secrets, authorization codes, and tokens are stored in the database.

const (
	// StoreModePlain stores tokens and secrets in plain text (suitable for local dev/testing).
	StoreModePlain StoreMode = "plain"

	// StoreModeHashed stores tokens and secrets hashed via SHA-256.
	StoreModeHashed StoreMode = "hashed"

	// StoreModeEncrypted stores tokens and secrets encrypted via AES-256-GCM.
	StoreModeEncrypted StoreMode = "encrypted"
)

type SubjectType

type SubjectType string

SubjectType defines how the subject identifier (sub claim) is generated in OpenID Connect.

const (
	// SubjectTypePublic issues the exact same sub identifier across all clients.
	SubjectTypePublic SubjectType = "public"

	// SubjectTypePairwise issues client-specific pseudonymous sub identifiers.
	SubjectTypePairwise SubjectType = "pairwise"
)

type TokenEndpointAuthMethod

type TokenEndpointAuthMethod string

TokenEndpointAuthMethod specifies client authentication methods at the token endpoint.

const (
	// AuthMethodClientSecretBasic authenticates via HTTP Basic Authorization header.
	AuthMethodClientSecretBasic TokenEndpointAuthMethod = "client_secret_basic"

	// AuthMethodClientSecretPost authenticates via POST body parameters (client_id & client_secret).
	AuthMethodClientSecretPost TokenEndpointAuthMethod = "client_secret_post"

	// AuthMethodNone indicates no client authentication (public clients with PKCE).
	AuthMethodNone TokenEndpointAuthMethod = "none"
)

type TokenIssuedEventPayload

type TokenIssuedEventPayload struct {
	// ClientID is the client receiving tokens.
	ClientID string `json:"client_id"`

	// UserID is the user ID if issued in user context (nil for M2M client credentials).
	UserID *string `json:"user_id,omitempty"`

	// GrantType is the grant type used for issuance.
	GrantType GrantType `json:"grant_type"`

	// Scopes is the list of scopes granted to the tokens.
	Scopes []string `json:"scopes"`

	// AccessToken is the raw access token string.
	AccessToken string `json:"access_token"`

	// RefreshToken is the raw refresh token string, if issued.
	RefreshToken *string `json:"refresh_token,omitempty"`

	// IDToken is the raw ID token string, if issued.
	IDToken *string `json:"id_token,omitempty"`

	// Timestamp is the moment the tokens were issued.
	Timestamp time.Time `json:"timestamp"`
}

TokenIssuedEventPayload represents the payload dispatched when tokens are minted.

type TokenParams

type TokenParams struct {
	GrantType    string `json:"grant_type"`
	Code         string `json:"code,omitempty"`
	CodeVerifier string `json:"code_verifier,omitempty"`
	RedirectURI  string `json:"redirect_uri,omitempty"`
	ClientID     string `json:"client_id,omitempty"`
	ClientSecret string `json:"client_secret,omitempty"`
	RefreshToken string `json:"refresh_token,omitempty"`
	Scope        string `json:"scope,omitempty"`
	Resource     string `json:"resource,omitempty"`
	plugin.ExtraContainer
}

TokenParams defines input parameters for the token endpoint exchange.

type TokenRefreshedEventPayload

type TokenRefreshedEventPayload struct {
	// ClientID is the client refreshing tokens.
	ClientID string `json:"client_id"`

	// UserID is the user ID associated with the tokens.
	UserID string `json:"user_id"`

	// FamilyID is the token family identifier.
	FamilyID string `json:"family_id"`

	// NewAccessToken is the newly issued access token.
	NewAccessToken string `json:"new_access_token"`

	// NewRefreshToken is the newly rotated refresh token.
	NewRefreshToken string `json:"new_refresh_token"`

	// Timestamp is the moment the refresh occurred.
	Timestamp time.Time `json:"timestamp"`
}

TokenRefreshedEventPayload represents the payload dispatched upon token refresh rotation.

type TokenResult

type TokenResult struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	RefreshToken string `json:"refresh_token,omitempty"`
	IDToken      string `json:"id_token,omitempty"`
	Scope        string `json:"scope,omitempty"`
}

TokenResult represents the response issued by the token endpoint.

type TokenRevokedEventPayload

type TokenRevokedEventPayload struct {
	// TokenHash is the SHA-256 hash of the revoked token.
	TokenHash string `json:"token_hash"`

	// TokenType is the hinted type ("access_token" or "refresh_token").
	TokenType string `json:"token_type"`

	// ClientID is the client ID associated with the token, if known.
	ClientID string `json:"client_id,omitempty"`

	// Timestamp is the moment revocation occurred.
	Timestamp time.Time `json:"timestamp"`
}

TokenRevokedEventPayload represents the payload dispatched when a token is revoked.

type UpdateClientParams

type UpdateClientParams struct {
	ClientID               string         `json:"client_id"`
	ClientName             *string        `json:"client_name,omitempty"`
	ClientURI              *string        `json:"client_uri,omitempty"`
	LogoURI                *string        `json:"logo_uri,omitempty"`
	Contacts               []string       `json:"contacts,omitempty"`
	RedirectURIs           []string       `json:"redirect_uris,omitempty"`
	PostLogoutRedirectURIs []string       `json:"post_logout_redirect_uris,omitempty"`
	GrantTypes             []GrantType    `json:"grant_types,omitempty"`
	Scopes                 []string       `json:"scopes,omitempty"`
	SkipConsent            *bool          `json:"skip_consent,omitempty"`
	EnableEndSession       *bool          `json:"enable_end_session,omitempty"`
	Disabled               *bool          `json:"disabled,omitempty"`
	Metadata               map[string]any `json:"metadata,omitempty"`
	plugin.ExtraContainer
}

UpdateClientParams defines input parameters to update an OAuth client.

type UpdateClientResult

type UpdateClientResult struct {
	Client *OAuthClient `json:"client"`
}

UpdateClientResult contains the updated client entity.

type UserInfoParams

type UserInfoParams struct {
	AccessToken string `json:"access_token"`
	plugin.ExtraContainer
}

UserInfoParams defines input parameters for the OIDC UserInfo endpoint.

type UserInfoResult

type UserInfoResult struct {
	Sub                 string         `json:"sub"`
	Name                string         `json:"name,omitempty"`
	Email               string         `json:"email,omitempty"`
	EmailVerified       *bool          `json:"email_verified,omitempty"`
	PhoneNumber         string         `json:"phone_number,omitempty"`
	PhoneNumberVerified *bool          `json:"phone_number_verified,omitempty"`
	Picture             string         `json:"picture,omitempty"`
	Claims              map[string]any `json:"claims,omitempty"`
}

UserInfoResult represents claims returned by the OIDC UserInfo endpoint.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL