Documentation
¶
Index ¶
- Constants
- Variables
- func ConstantTimeEqual(a, b string) bool
- func GenerateBase64URLToken(bytesLength int) (string, error)
- func GenerateRandomString(length int) (string, error)
- func HasAllScopes(grantedScopes, requestedScopes []string) bool
- func HasScope(scopes []string, target string) bool
- func NormalizeScopes(scopes []string) string
- func ParseScopes(scopeStr string) []string
- func ValidatePKCE(codeVerifier, codeChallenge, codeChallengeMethod string, allowPlain bool) bool
- func ValidateRedirectURI(requestedURI string, allowedURIs []string) bool
- type AdditionalClaimsFunc
- type AuthorizeParams
- type AuthorizeResponse
- type ClientType
- type Config
- type DiscoveryMetadata
- type ExchangeTokenParams
- type GrantConsentParams
- type JWKKey
- type JWKS
- type OAuthClient
- type OAuthCode
- type OAuthConsent
- type OAuthToken
- type OIDCAuthCodeIssuedPayload
- type OIDCClientRegisteredPayload
- type OIDCConsentGrantedPayload
- type OIDCConsentRevokedPayload
- type OIDCTokenIssuedPayload
- type OIDCTokenRefreshedPayload
- type Option
- func WithAdditionalClaims(fn AdditionalClaimsFunc) Option
- func WithAllowPlainCodeChallenge(allow bool) Option
- func WithBaseURL(url string) Option
- func WithConsentPageURL(url string) Option
- func WithIssuer(issuer string) Option
- func WithLoginPageURL(url string) Option
- func WithRSAKeys(privateKey *rsa.PrivateKey) Option
- func WithRequirePKCE(require bool) Option
- func WithSecretKey(secret []byte) Option
- func WithStoreClientSecretMode(mode SecretStoreMode) Option
- func WithSupportedScopes(scopes []string) Option
- func WithTokenExpirations(access, refresh, code time.Duration) Option
- type Plugin
- func (p *Plugin) Authorize(ctx context.Context, params AuthorizeParams) (*AuthorizeResponse, error)
- func (p *Plugin) Config() Config
- func (p *Plugin) EndSession(ctx context.Context, idTokenHint string, postLogoutRedirectURI *string) (string, error)
- func (p *Plugin) ExchangeToken(ctx context.Context, params ExchangeTokenParams) (*TokenResponse, error)
- func (p *Plugin) GenerateIDToken(ctx context.Context, user *entity.User, client *OAuthClient, scope string, ...) (string, error)
- func (p *Plugin) GetClient(ctx context.Context, clientID string) (*OAuthClient, error)
- func (p *Plugin) GetDiscoveryMetadata(ctx context.Context) (*DiscoveryMetadata, error)
- func (p *Plugin) GetJWKS(ctx context.Context) (map[string]any, error)
- func (p *Plugin) GetUserInfo(ctx context.Context, accessToken string) (UserInfoClaims, error)
- func (p *Plugin) GrantConsent(ctx context.Context, params GrantConsentParams) (*AuthorizeResponse, error)
- func (p *Plugin) ID() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) RegisterClient(ctx context.Context, params RegisterClientParams) (*OAuthClient, error)
- func (p *Plugin) ServeDiscoveryMetadata(w http.ResponseWriter, r *http.Request)
- func (p *Plugin) ServeJWKS(w http.ResponseWriter, r *http.Request)
- func (p *Plugin) VerifyJWT(tokenStr string) (map[string]any, error)
- type RegisterClientParams
- type Repository
- type SecretStoreMode
- type TokenResponse
- type UserInfoClaims
Constants ¶
const ( // EventOIDCClientRegistered is published when a new OAuth client is registered. EventOIDCClientRegistered = "oidc:client_registered" // EventOIDCAuthCodeIssued is published when an authorization code is successfully generated. EventOIDCAuthCodeIssued = "oidc:auth_code_issued" // EventOIDCTokenIssued is published when tokens (Access, Refresh, ID Token) are issued. EventOIDCTokenIssued = "oidc:token_issued" // EventOIDCTokenRefreshed is published when tokens are exchanged via a refresh token. EventOIDCTokenRefreshed = "oidc:token_refreshed" // EventOIDCConsentGranted is published when a user grants scope consent to a client. EventOIDCConsentGranted = "oidc:consent_granted" // EventOIDCConsentRevoked is published when user consent for a client is revoked. EventOIDCConsentRevoked = "oidc:consent_revoked" )
const DefaultJWKKeyID = "oidc-provider-key-1"
const GrantTypeAuthorizationCode = "authorization_code"
GrantTypeAuthorizationCode is the RFC 6749 authorization_code grant type string.
const GrantTypeRefreshToken = "refresh_token"
GrantTypeRefreshToken is the RFC 6749 refresh_token grant type string.
const PluginID = "oidc-provider"
PluginID is the unique string identifier for the OIDC Provider plugin ("oidc-provider").
Variables ¶
var ( // ErrInvalidClient is returned when client authentication fails or the client application is disabled. ErrInvalidClient = errors.New("invalid_client: client authentication failed or client disabled") // ErrInvalidGrant is returned when an authorization code or refresh token is invalid, expired, or revoked. ErrInvalidGrant = errors.New("invalid_grant: invalid, expired, or revoked authorization code/refresh token") // ErrInvalidRequest is returned when required parameters are missing or malformed. ErrInvalidRequest = errors.New("invalid_request: missing or invalid parameters") ErrUnauthorizedClient = errors.New("unauthorized_client: client is not allowed to use this grant type") // ErrUnsupportedGrantType is returned when the requested grant_type is unsupported. ErrUnsupportedGrantType = errors.New("unsupported_grant_type: grant type is not supported") // ErrInvalidScope is returned when the requested scope is invalid or exceeds granted scope. ErrInvalidScope = errors.New("invalid_scope: scope is invalid or not granted") // ErrAccessDenied is returned when the resource owner or authorization server denies the request. ErrAccessDenied = errors.New("access_denied: resource owner or authorization server denied request") // ErrCodeAlreadyConsumed is returned when an authorization code is reused, triggering token revocation. ErrCodeAlreadyConsumed = errors.New("invalid_grant: authorization code has already been used") // ErrPKCEValidationFailed is returned when code_verifier fails SHA256/plain comparison against code_challenge. ErrPKCEValidationFailed = errors.New("invalid_grant: code_verifier does not match code_challenge") // ErrUserNotFound is returned when the user associated with a grant or token cannot be found. ErrUserNotFound = errors.New("oidcprovider: user not found") // ErrConsentRequired is returned when interactive user consent is required before authorization. ErrConsentRequired = errors.New("oidcprovider: user consent required") // ErrInvalidConsentCode is returned when a consent validation code is invalid or expired. ErrInvalidConsentCode = errors.New("oidcprovider: invalid consent code") )
Sentinel errors for the OIDC Provider plugin (RFC 6749 & OpenID Connect Core compliant).
Functions ¶
func ConstantTimeEqual ¶
ConstantTimeEqual performs a constant-time comparison of two strings to prevent timing attacks.
func GenerateBase64URLToken ¶
GenerateBase64URLToken generates a cryptographically secure base64url token string.
func GenerateRandomString ¶
GenerateRandomString generates a cryptographically secure random string of specified length.
func HasAllScopes ¶
HasAllScopes checks if all requestedScopes are present in grantedScopes.
func NormalizeScopes ¶
NormalizeScopes joins a slice of scope strings into a single space-delimited string.
func ParseScopes ¶
ParseScopes splits a space-delimited scope string into a clean slice of scope strings.
func ValidatePKCE ¶
ValidatePKCE verifies a PKCE code_verifier against a code_challenge using the specified method (RFC 7636).
func ValidateRedirectURI ¶
ValidateRedirectURI checks if requestedURI strictly matches one of the client's registered redirect_uris.
Types ¶
type AdditionalClaimsFunc ¶
type AdditionalClaimsFunc func(ctx context.Context, user *entity.User, scopes []string, client *OAuthClient) map[string]any
AdditionalClaimsFunc defines a custom callback to append custom claims to ID Tokens or UserInfo responses.
type AuthorizeParams ¶
type AuthorizeParams struct {
ClientID string `json:"client_id"`
RedirectURI string `json:"redirect_uri"`
ResponseType string `json:"response_type"` // Must be "code"
Scope string `json:"scope"`
State *string `json:"state,omitempty"`
Nonce *string `json:"nonce,omitempty"`
CodeChallenge *string `json:"code_challenge,omitempty"`
CodeChallengeMethod *string `json:"code_challenge_method,omitempty"`
Prompt *string `json:"prompt,omitempty"` // "consent", "login", "none"
UserID string `json:"user_id"`
}
AuthorizeParams holds input parameters for an authorization request.
type AuthorizeResponse ¶
type AuthorizeResponse struct {
RedirectURI string `json:"redirect_uri"`
Code *string `json:"code,omitempty"`
State *string `json:"state,omitempty"`
RequiresConsent bool `json:"requires_consent"`
ConsentCode *string `json:"consent_code,omitempty"`
ScopesRequested []string `json:"scopes_requested,omitempty"`
ClientInfo *OAuthClient `json:"client_info,omitempty"`
}
AuthorizeResponse holds the outcome of an authorization request.
type ClientType ¶
type ClientType string
ClientType defines the OAuth 2.0 / OIDC client application type.
const ( // ClientTypeWeb represents confidential server-side web applications capable of keeping secrets. ClientTypeWeb ClientType = "web" // ClientTypeNative represents native mobile or desktop applications. ClientTypeNative ClientType = "native" // ClientTypeUserAgentBased represents Single Page Applications (SPAs) executing in a browser. ClientTypeUserAgentBased ClientType = "user-agent-based" // ClientTypePublic represents public clients incapable of storing client secrets securely. ClientTypePublic ClientType = "public" )
type Config ¶
type Config struct {
Issuer string
BaseURL string
AccessTokenExpiresIn time.Duration
RefreshTokenExpiresIn time.Duration
CodeExpiresIn time.Duration
SupportedScopes []string
DefaultScope string
RequirePKCE bool
AllowPlainCodeChallenge bool
AllowDynamicClientRegistration bool
StoreClientSecretMode SecretStoreMode
SigningAlgorithm string // "RS256" or "HS256"
PrivateKey *rsa.PrivateKey
SecretKey []byte
ConsentPageURL *string
LoginPageURL string
GetAdditionalClaims AdditionalClaimsFunc
}
Config holds configuration settings for the OIDC Provider plugin.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns a Config struct pre-populated with standard OIDC defaults.
type DiscoveryMetadata ¶
type DiscoveryMetadata struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
UserinfoEndpoint string `json:"userinfo_endpoint"`
JwksURI string `json:"jwks_uri"`
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
ScopesSupported []string `json:"scopes_supported"`
ResponseTypesSupported []string `json:"response_types_supported"`
ResponseModesSupported []string `json:"response_modes_supported"`
GrantTypesSupported []string `json:"grant_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
}
DiscoveryMetadata represents the OpenID Connect Discovery 1.0 JSON payload (/.well-known/openid-configuration).
type ExchangeTokenParams ¶
type ExchangeTokenParams struct {
GrantType string `json:"grant_type"` // "authorization_code" or "refresh_token"
Code *string `json:"code,omitempty"`
RefreshToken *string `json:"refresh_token,omitempty"`
RedirectURI *string `json:"redirect_uri,omitempty"`
ClientID string `json:"client_id"`
ClientSecret *string `json:"client_secret,omitempty"`
CodeVerifier *string `json:"code_verifier,omitempty"`
}
ExchangeTokenParams holds parameters submitted to the token endpoint.
type GrantConsentParams ¶
type GrantConsentParams struct {
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
ConsentCode string `json:"consent_code"`
Accept bool `json:"accept"`
Scopes []string `json:"scopes"`
}
GrantConsentParams holds input parameters when an authenticated user approves client scopes.
type JWKKey ¶
type JWKKey struct {
Kty string `json:"kty"`
Use string `json:"use"`
Alg string `json:"alg"`
Kid string `json:"kid"`
N string `json:"n,omitempty"`
E string `json:"e,omitempty"`
K string `json:"k,omitempty"`
}
JWKKey represents a single JSON Web Key in a JWKS set.
type JWKS ¶
type JWKS struct {
Keys []JWKKey `json:"keys"`
}
JWKS represents a JSON Web Key Set payload.
type OAuthClient ¶
type OAuthClient struct {
ID string `json:"id"`
ClientID string `json:"client_id"`
ClientSecret *string `json:"client_secret,omitempty"`
Type ClientType `json:"type"`
Name string `json:"name"`
Icon *string `json:"icon,omitempty"`
Metadata *string `json:"metadata,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
Disabled bool `json:"disabled"`
UserID *string `json:"user_id,omitempty"`
SkipConsent bool `json:"skip_consent,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OAuthClient represents a registered OAuth 2.0 / OIDC client application entity.
type OAuthCode ¶
type OAuthCode struct {
ID string `json:"id"`
Code string `json:"code"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
RedirectURI string `json:"redirect_uri"`
Scope string `json:"scope"`
State *string `json:"state,omitempty"`
Nonce *string `json:"nonce,omitempty"`
CodeChallenge *string `json:"code_challenge,omitempty"`
CodeChallengeMethod *string `json:"code_challenge_method,omitempty"`
ExpiresAt time.Time `json:"expires_at"`
Consumed bool `json:"consumed"`
CreatedAt time.Time `json:"created_at"`
}
OAuthCode represents a single-use authorization code grant (RFC 6749 4.1.2).
type OAuthConsent ¶
type OAuthConsent struct {
ID string `json:"id"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
Scopes string `json:"scopes"`
ConsentGiven bool `json:"consent_given"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OAuthConsent represents explicit user consent granted to a client application.
type OAuthToken ¶
type OAuthToken struct {
ID string `json:"id"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
Scope string `json:"scope"`
AccessTokenExpiresAt time.Time `json:"access_token_expires_at"`
RefreshTokenExpiresAt time.Time `json:"refresh_token_expires_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
OAuthToken represents an Access Token and Refresh Token pair entity.
type OIDCAuthCodeIssuedPayload ¶
type OIDCAuthCodeIssuedPayload struct {
Code string `json:"code"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
}
OIDCAuthCodeIssuedPayload defines the event bus payload when an authorization code is issued.
type OIDCClientRegisteredPayload ¶
type OIDCClientRegisteredPayload struct {
Client *OAuthClient `json:"client"`
}
OIDCClientRegisteredPayload defines the event bus payload when a client application is created.
type OIDCConsentGrantedPayload ¶
type OIDCConsentGrantedPayload struct {
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
Scopes []string `json:"scopes"`
}
OIDCConsentGrantedPayload defines the event bus payload when consent is given.
type OIDCConsentRevokedPayload ¶
type OIDCConsentRevokedPayload struct {
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
}
OIDCConsentRevokedPayload defines the event bus payload when consent is revoked.
type OIDCTokenIssuedPayload ¶
type OIDCTokenIssuedPayload struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token,omitempty"`
IDToken string `json:"id_token,omitempty"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
}
OIDCTokenIssuedPayload defines the event bus payload when an access/id token is issued.
type OIDCTokenRefreshedPayload ¶
type OIDCTokenRefreshedPayload struct {
NewAccessToken string `json:"new_access_token"`
NewRefreshToken string `json:"new_refresh_token,omitempty"`
ClientID string `json:"client_id"`
UserID string `json:"user_id"`
}
OIDCTokenRefreshedPayload defines the event bus payload when tokens are refreshed.
type Option ¶
type Option func(*Config)
Option represents a functional option for configuring the OIDC Provider plugin.
func WithAdditionalClaims ¶
func WithAdditionalClaims(fn AdditionalClaimsFunc) Option
WithAdditionalClaims registers a callback to inject custom claims into UserInfo and ID Tokens.
func WithAllowPlainCodeChallenge ¶
WithAllowPlainCodeChallenge enables plain code_challenge_method in PKCE (not recommended).
func WithBaseURL ¶
WithBaseURL sets the base URL used to construct endpoint paths.
func WithConsentPageURL ¶
WithConsentPageURL sets the URL of the consent UI page.
func WithIssuer ¶
WithIssuer sets the OIDC issuer identifier URL (e.g. "https://auth.example.com").
func WithLoginPageURL ¶
WithLoginPageURL sets the login redirect URL.
func WithRSAKeys ¶
func WithRSAKeys(privateKey *rsa.PrivateKey) Option
WithRSAKeys configures an RSA private key for RS256 ID Token signing and JWKS export.
func WithRequirePKCE ¶
WithRequirePKCE enforces PKCE (RFC 7636) for authorization code grant requests.
func WithSecretKey ¶
WithSecretKey configures a shared secret key for HS256 ID Token signing.
func WithStoreClientSecretMode ¶
func WithStoreClientSecretMode(mode SecretStoreMode) Option
WithStoreClientSecretMode sets how client_secret values are stored and compared.
func WithSupportedScopes ¶
WithSupportedScopes sets the list of supported OIDC scopes.
func WithTokenExpirations ¶
WithTokenExpirations sets access token, refresh token, and authorization code expiration durations.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements the OpenID Connect 1.0 / OAuth 2.0 Provider plugin for go-modular-auth.
func New ¶
func New(repo Repository, opts ...Option) *Plugin
New instantiates a new OIDC Provider plugin configured with the given repository and options.
func (*Plugin) Authorize ¶
func (p *Plugin) Authorize(ctx context.Context, params AuthorizeParams) (*AuthorizeResponse, error)
Authorize processes an OAuth 2.0 / OIDC authorization request.
func (*Plugin) EndSession ¶
func (p *Plugin) EndSession(ctx context.Context, idTokenHint string, postLogoutRedirectURI *string) (string, error)
EndSession processes RP-Initiated Logout.
func (*Plugin) ExchangeToken ¶
func (p *Plugin) ExchangeToken(ctx context.Context, params ExchangeTokenParams) (*TokenResponse, error)
ExchangeToken exchanges an authorization code or refresh token for Access, Refresh, and ID Tokens.
func (*Plugin) GenerateIDToken ¶
func (p *Plugin) GenerateIDToken(ctx context.Context, user *entity.User, client *OAuthClient, scope string, nonce *string, accessToken *string, expiresIn time.Duration) (string, error)
GenerateIDToken constructs and signs an OpenID Connect ID Token JWT.
func (*Plugin) GetDiscoveryMetadata ¶
func (p *Plugin) GetDiscoveryMetadata(ctx context.Context) (*DiscoveryMetadata, error)
GetDiscoveryMetadata generates the OpenID Connect Discovery 1.0 JSON configuration metadata.
func (*Plugin) GetUserInfo ¶
GetUserInfo returns standard OIDC UserInfo claims for a valid access_token.
func (*Plugin) GrantConsent ¶
func (p *Plugin) GrantConsent(ctx context.Context, params GrantConsentParams) (*AuthorizeResponse, error)
GrantConsent saves user consent and returns authorization parameters.
func (*Plugin) RegisterClient ¶
func (p *Plugin) RegisterClient(ctx context.Context, params RegisterClientParams) (*OAuthClient, error)
RegisterClient registers a new OAuth 2.0 / OIDC client application.
func (*Plugin) ServeDiscoveryMetadata ¶ added in v0.20.0
func (p *Plugin) ServeDiscoveryMetadata(w http.ResponseWriter, r *http.Request)
ServeDiscoveryMetadata is a net/http handler for serving /.well-known/openid-configuration.
type RegisterClientParams ¶
type RegisterClientParams struct {
Name string `json:"name"`
Type ClientType `json:"type"`
RedirectURIs []string `json:"redirect_uris"`
Icon *string `json:"icon,omitempty"`
Metadata *string `json:"metadata,omitempty"`
UserID *string `json:"user_id,omitempty"`
SkipConsent bool `json:"skip_consent,omitempty"`
}
RegisterClientParams holds input parameters when registering a new OAuth/OIDC client application.
type Repository ¶
type Repository interface {
// CreateClient persists a new OAuth client application in storage.
//
// Function:
// Used during dynamic client registration or administrative client creation.
//
// Storage:
// Database (GORM / SQL) - Relational client entity persistence.
//
// Arguments:
// - ctx: Request cancellation context.
// - client: The OAuthClient entity to persist.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// INSERT INTO oidc_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
// FindByClientID retrieves an OAuth client application by its public client_id.
//
// Function:
// Used during authorize, token exchange, userinfo, and client authentication requests.
//
// Storage:
// Both (Cache-Aside Strategy) - Cached by client_id in Redis/memory.
//
// Arguments:
// - ctx: Request cancellation context.
// - clientID: The unique public OAuth client ID.
//
// Returns:
// - *OAuthClient: Matching OAuth client entity if found.
// - error: ErrInvalidClient if not found, or database error.
//
// Example SQL:
// SELECT id, client_id, client_secret, name, redirect_uris, grant_types, created_at, updated_at FROM oidc_clients WHERE client_id = $1 LIMIT 1;
//
// Example Cache (Redis):
// val, err := rdb.Get(ctx, "oidc:client:" + clientID).Bytes()
FindByClientID(ctx context.Context, clientID string) (*OAuthClient, error)
// UpdateClient updates mutable fields of an existing OAuth client.
//
// Function:
// Used during administrative client updates or secret rotation.
//
// Storage:
// Database (GORM / SQL) - Client update.
//
// Arguments:
// - ctx: Request cancellation context.
// - client: Modified OAuthClient entity.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// UPDATE oidc_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 persistent storage by client_id.
//
// Function:
// Used when unregistering or purging an OAuth client application.
//
// Storage:
// Database (GORM / SQL) - Client record removal.
//
// Arguments:
// - ctx: Request cancellation context.
// - clientID: The unique public OAuth client ID.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// DELETE FROM oidc_clients WHERE client_id = $1;
DeleteClient(ctx context.Context, clientID string) error
// ListClientsByUserID retrieves all OAuth clients owned/registered by a specific user.
//
// Function:
// Used in developer portals or user settings to list user-created OAuth applications.
//
// Storage:
// Database (GORM / SQL) - User client apps query.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: The unique user identifier.
//
// Returns:
// - []*OAuthClient: Slice of matching OAuth clients.
// - error: Nil on success, or database error.
//
// Example SQL:
// SELECT id, client_id, client_secret, name, redirect_uris, grant_types, created_at, updated_at FROM oidc_clients WHERE user_id = $1;
ListClientsByUserID(ctx context.Context, userID string) ([]*OAuthClient, error)
// CreateAuthorizationCode persists a new single-use authorization code grant.
//
// Function:
// Called at the end of the authorization flow after user consent.
//
// Storage:
// Cache (Redis / In-Memory TTL) - Short-lived authorization code state.
//
// Arguments:
// - ctx: Request cancellation context.
// - code: OAuthCode entity containing code secret, PKCE challenge, and granted scopes.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// INSERT INTO oidc_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, "oidc:code:" + code.Code, bytes, ttl).Err()
CreateAuthorizationCode(ctx context.Context, code *OAuthCode) error
// ConsumeAuthorizationCode atomically retrieves and invalidates/deletes an authorization code record.
//
// Function:
// Called during authorization_code token exchange to prevent code reuse and replay attacks.
//
// Storage:
// Cache (Redis GETDEL / Memory) - Atomic read-and-delete single-use code consumption.
//
// Arguments:
// - ctx: Request cancellation context.
// - code: The authorization code string secret.
//
// Returns:
// - *OAuthCode: The consumed code grant entity if valid.
// - error: ErrInvalidGrant if missing or expired, ErrCodeAlreadyConsumed if reused.
//
// Example SQL:
// DELETE FROM oidc_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, "oidc:code:" + code).Bytes()
ConsumeAuthorizationCode(ctx context.Context, code string) (*OAuthCode, error)
// DeleteExpiredCodes purges all expired authorization codes from storage.
//
// Function:
// Called by background cleanup tasks or maintenance crons.
//
// Storage:
// Database (GORM / SQL) - Bulk code deletion.
//
// Arguments:
// - ctx: Request cancellation context.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// DELETE FROM oidc_codes WHERE expires_at <= $1;
DeleteExpiredCodes(ctx context.Context) error
// CreateTokenPair persists a new access token (and optional refresh token) grant.
//
// Function:
// Called during token issuance for authorization_code, refresh_token, or client_credentials grants.
//
// Storage:
// Database (GORM / SQL) - Token pair insertion.
//
// Arguments:
// - ctx: Request cancellation context.
// - token: OAuthToken entity containing access_token, refresh_token, and expiration details.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// INSERT INTO oidc_tokens (id, access_token, refresh_token, client_id, user_id, scope, access_token_expires_at, refresh_token_expires_at, revoked, created_at)
// VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10);
CreateTokenPair(ctx context.Context, token *OAuthToken) error
// FindByAccessToken retrieves token details by matching access_token string.
//
// Function:
// Used during Introspection, UserInfo, or API authorization token validation.
//
// Storage:
// Both (Cache-Aside Strategy) - Cached in Redis (`oidc:token:<accessToken>`) for fast token validation.
//
// Arguments:
// - ctx: Request cancellation context.
// - accessToken: The raw access token string.
//
// Returns:
// - *OAuthToken: Matching token grant if found and active.
// - error: ErrInvalidGrant if missing, revoked, or expired.
//
// Example SQL:
// SELECT id, access_token, refresh_token, client_id, user_id, scope, access_token_expires_at, refresh_token_expires_at, revoked, created_at FROM oidc_tokens WHERE access_token = $1 LIMIT 1;
//
// Example Cache (Redis):
// val, err := rdb.Get(ctx, "oidc:token:" + accessToken).Bytes()
FindByAccessToken(ctx context.Context, accessToken string) (*OAuthToken, error)
// FindByRefreshToken retrieves token grant details matching a refresh_token string.
//
// Function:
// Called during refresh_token grant type token renewal.
//
// Storage:
// Database (GORM / SQL) - Refresh token query.
//
// Arguments:
// - ctx: Request cancellation context.
// - refreshToken: The raw refresh token string.
//
// Returns:
// - *OAuthToken: Matching token grant if found and valid.
// - error: ErrInvalidGrant if missing or expired, ErrRefreshTokenRevoked if already revoked.
//
// Example SQL:
// SELECT id, access_token, refresh_token, client_id, user_id, scope, access_token_expires_at, refresh_token_expires_at, revoked, created_at FROM oidc_tokens WHERE refresh_token = $1 LIMIT 1;
FindByRefreshToken(ctx context.Context, refreshToken string) (*OAuthToken, error)
// RevokeTokenPair marks a specific token grant (by token ID or token string) as revoked.
//
// Function:
// Called during RFC 7009 Token Revocation or session sign-out.
//
// Storage:
// Database (GORM / SQL) - Revocation status update.
//
// Arguments:
// - ctx: Request cancellation context.
// - tokenID: Primary record ID or token identifier.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// UPDATE oidc_tokens SET revoked = true WHERE id = $1 OR access_token = $1 OR refresh_token = $1;
RevokeTokenPair(ctx context.Context, tokenID string) error
// RevokeTokensByClientIDAndUserID revokes all active token grants issued to a user for a specific client.
//
// Function:
// Called when a user revokes access to a third-party client application.
//
// Storage:
// Database (GORM / SQL) - Bulk token revocation update.
//
// Arguments:
// - ctx: Request cancellation context.
// - clientID: OAuth client identifier.
// - userID: Target user identifier.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// UPDATE oidc_tokens SET revoked = true WHERE client_id = $1 AND user_id = $2;
RevokeTokensByClientIDAndUserID(ctx context.Context, clientID, userID string) error
// DeleteExpiredTokens purges all expired and revoked token records from storage.
//
// Function:
// Called by maintenance tasks to keep storage size optimal.
//
// Storage:
// Database (GORM / SQL) - Bulk token deletion.
//
// Arguments:
// - ctx: Request cancellation context.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// DELETE FROM oidc_tokens WHERE refresh_token_expires_at <= $1 OR (refresh_token IS NULL AND access_token_expires_at <= $1);
DeleteExpiredTokens(ctx context.Context) error
// GetConsent retrieves persistent user consent granted to a client application.
//
// Function:
// Called during interactive authorization to check if prompt=none or remembered consent applies.
//
// Storage:
// Database (GORM / SQL) - Consent record query.
//
// Arguments:
// - ctx: Request cancellation context.
// - clientID: Target OAuth client ID.
// - userID: User identifier.
//
// Returns:
// - *OAuthConsent: User consent record if found.
// - error: ErrConsentRequired if not consented, or database error.
//
// Example SQL:
// SELECT id, client_id, user_id, scopes, granted_at FROM oidc_consents WHERE client_id = $1 AND user_id = $2 LIMIT 1;
GetConsent(ctx context.Context, clientID, userID string) (*OAuthConsent, error)
// SaveConsent creates or updates remembered user consent for a client application.
//
// Function:
// Called when a user approves scopes during authorization prompt.
//
// Storage:
// Database (GORM / SQL) - Consent record insertion/upsert.
//
// Arguments:
// - ctx: Request cancellation context.
// - consent: OAuthConsent entity to persist.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// INSERT INTO oidc_consents (id, client_id, user_id, scopes, granted_at) VALUES ($1, $2, $3, $4, $5)
// ON CONFLICT (client_id, user_id) DO UPDATE SET scopes = $4, granted_at = $5;
SaveConsent(ctx context.Context, consent *OAuthConsent) error
// RevokeConsent removes remembered consent granted by a user to a client application.
//
// Function:
// Called when a user disconnects an authorized application in account settings.
//
// Storage:
// Database (GORM / SQL) - Consent record deletion.
//
// Arguments:
// - ctx: Request cancellation context.
// - clientID: Target OAuth client ID.
// - userID: User identifier.
//
// Returns:
// - error: Nil on success, or database error.
//
// Example SQL:
// DELETE FROM oidc_consents WHERE client_id = $1 AND user_id = $2;
RevokeConsent(ctx context.Context, clientID, userID string) error
// GetUserByID fetches user profile details to populate UserInfo response claims.
//
// Function:
// Called during OpenID Connect /userinfo endpoint processing or ID token claim assembly.
//
// Storage:
// Database (GORM / SQL) - User primary key lookup.
//
// Arguments:
// - ctx: Request cancellation context.
// - userID: Target user identifier.
//
// Returns:
// - *entity.User: Matching user entity if found.
// - error: ErrUserNotFound if missing, or database error.
//
// Example SQL:
// SELECT id, email, name, email_verified, created_at, updated_at FROM users WHERE id = $1 LIMIT 1;
GetUserByID(ctx context.Context, userID string) (*entity.User, error)
}
Repository defines the persistent storage contract required by the OIDC Provider plugin. Implement this interface on your custom database adapter (e.g. PostgreSQL, MySQL, SQLite, MongoDB, GORM).
Implementation Example (GORM / database/sql): ¶
type GormOIDCProviderRepository struct {
db *gorm.DB
}
func (r *GormOIDCProviderRepository) FindByClientID(ctx context.Context, clientID string) (*oidcprovider.OAuthClient, error) {
var c oidcprovider.OAuthClient
if err := r.db.WithContext(ctx).Where("client_id = ?", clientID).First(&c).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, oidcprovider.ErrInvalidClient
}
return nil, err
}
return &c, nil
}
Storage and Caching Recommendation (Token Introspection & Authorization Code Cache): ¶
High-traffic OIDC Provider deployments benefit greatly from caching access tokens and client credentials:
Access Token Introspection (`FindByAccessToken`): Cache access token grants in Redis (`oidc:token:<accessToken>`) with TTL matching `access_token_expires_at`.
Authorization Codes (`ConsumeAuthorizationCode`): Store single-use codes in Redis (`oidc:code:<code>`) and consume via `GETDEL` for single-use replay protection.
Recommended Caching Decorator Example:
type CachedOIDCProviderRepository struct {
dbRepo oidcprovider.Repository
redis *redis.Client
}
func (r *CachedOIDCProviderRepository) FindByAccessToken(ctx context.Context, tokenStr string) (*oidcprovider.OAuthToken, error) {
val, err := r.redis.Get(ctx, "oidc:token:"+tokenStr).Bytes()
if err == nil {
var token oidcprovider.OAuthToken
if json.Unmarshal(val, &token) == nil {
return &token, nil // Fast Introspection Cache Hit
}
}
token, err := r.dbRepo.FindByAccessToken(ctx, tokenStr)
if err == nil {
bytes, _ := json.Marshal(token)
ttl := time.Until(token.AccessTokenExpiresAt)
r.redis.Set(ctx, "oidc:token:"+tokenStr, bytes, ttl)
}
return token, err
}
type SecretStoreMode ¶
type SecretStoreMode string
SecretStoreMode specifies how client_secret values are stored and verified.
const ( // SecretStorePlain stores client_secret in plain text. SecretStorePlain SecretStoreMode = "plain" // SecretStoreHashed stores client_secret as a password hash (Argon2id/Bcrypt). SecretStoreHashed SecretStoreMode = "hashed" // SecretStoreEncrypted stores client_secret in encrypted form. SecretStoreEncrypted SecretStoreMode = "encrypted" )
type TokenResponse ¶
type TokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"` // "Bearer"
ExpiresIn int64 `json:"expires_in"` // seconds
RefreshToken string `json:"refresh_token,omitempty"`
IDToken string `json:"id_token,omitempty"`
Scope string `json:"scope,omitempty"`
}
TokenResponse represents a successful token issuance response.
type UserInfoClaims ¶
UserInfoClaims represents standard OpenID Connect UserInfo claims.