oidcprovider

package
v0.2.76 Latest Latest
Warning

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

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package oidcprovider contains the HTTP-agnostic OAuth 2.0/OIDC provider core.

The package deliberately knows nothing about Gin, net/http, GORM, cookies, or login pages. Applications provide authenticated users and persistence through the interfaces in this package.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidClient           = errors.New("invalid client")
	ErrInvalidRequest          = errors.New("invalid authorization request")
	ErrInvalidGrant            = errors.New("invalid grant")
	ErrInvalidScope            = errors.New("invalid scope")
	ErrLoginRequired           = errors.New("login required")
	ErrConsentRequired         = errors.New("consent required")
	ErrAccessDenied            = errors.New("access denied")
	ErrTokenRevoked            = errors.New("token revoked")
	ErrUnsupportedGrant        = errors.New("unsupported grant type")
	ErrUnsupportedResponse     = errors.New("unsupported response type")
	ErrUnsupportedResponseMode = errors.New("unsupported response mode")
	ErrServer                  = errors.New("provider internal error")
	ErrUserUnavailable         = errors.New("user is unavailable")
	ErrAuthorizationCodeReplay = errors.New("authorization code replay")
)

Functions

func GenerateClientSecret

func GenerateClientSecret() (string, error)

GenerateClientSecret returns a 256-bit, URL-safe client secret.

func HashClientSecret

func HashClientSecret(secret string) string

HashClientSecret returns the stable digest stored for a high-entropy client secret. Client secrets should be generated with GenerateClientSecret.

func MarshalRSAPrivateKeyPEM

func MarshalRSAPrivateKeyPEM(key *rsa.PrivateKey) ([]byte, error)

MarshalRSAPrivateKeyPEM encodes a signing key as unencrypted PKCS#8 PEM. Encryption at rest is the responsibility of the host's key store.

func ParseRSAPrivateKeyPEM

func ParseRSAPrivateKeyPEM(data []byte) (*rsa.PrivateKey, error)

func ValidateClient

func ValidateClient(client Client) error

ValidateClient checks the persistent registration independently of a request, allowing administrative code to reject invalid clients up front.

Types

type Authentication

type Authentication struct {
	UserID   string
	AuthTime time.Time
	// Fresh may only be set by a trusted host after it has verified a new
	// authentication ceremony for this authorization request. It satisfies
	// prompt=login and max_age even when AuthTime has second-level precision.
	Fresh bool
	// AuthID identifies a credential-verified authentication ceremony.
	// Federated sessions without upstream reauthentication proof leave it empty.
	AuthID string
}

Authentication is trusted state supplied by the host application, never parsed from authorization-request parameters.

type AuthorizationAction

type AuthorizationAction string
const (
	AuthorizationNeedLogin   AuthorizationAction = "login"
	AuthorizationNeedConsent AuthorizationAction = "consent"
	AuthorizationReady       AuthorizationAction = "ready"
)

type AuthorizationClient

type AuthorizationClient struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Public bool   `json:"public"`
}

AuthorizationClient is the non-sensitive client view returned to login and consent UIs. It intentionally excludes secret hashes and redirect lists.

type AuthorizationCode

type AuthorizationCode struct {
	Hash                string
	GrantID             string
	UserID              string
	ClientID            string
	RedirectURI         string
	Scopes              []string
	Nonce               string
	CodeChallenge       string
	CodeChallengeMethod string
	ExpiresAt           time.Time
	AuthTime            time.Time
	Used                bool
}

type AuthorizationCodeExchange

type AuthorizationCodeExchange struct {
	CodeHash     string
	ClientID     string
	RedirectURI  string
	CodeVerifier string
	Now          time.Time
	AccessToken  *Token
	RefreshToken *Token
}

AuthorizationCodeExchange describes the values that must still match when an authorization code is consumed and its tokens are persisted atomically.

type AuthorizationDecision

type AuthorizationDecision struct {
	Action AuthorizationAction
	Client AuthorizationClient
	Scopes []string
}

type AuthorizeRequest

type AuthorizeRequest struct {
	Request             string
	RequestURI          string
	IDTokenHint         string
	ClientID            string
	RedirectURI         string
	ResponseType        string
	ResponseMode        string
	Scope               []string
	State               string
	Nonce               string
	CodeChallenge       string
	CodeChallengeMethod string
	Prompt              []string
	MaxAge              *time.Duration
}

type AuthorizeResult

type AuthorizeResult struct {
	Code         string
	RedirectURI  string
	State        string
	Issuer       string
	ResponseMode string
}

type Client

type Client struct {
	ID                      string
	Name                    string
	SecretHash              string
	RedirectURIs            []string
	Scopes                  []string
	GrantTypes              []string
	TokenEndpointAuthMethod ClientAuthenticationMethod
	RequirePKCE             bool
	Public                  bool
	Enabled                 bool
}

type ClientAuthenticationMethod

type ClientAuthenticationMethod string
const (
	ClientAuthNone    ClientAuthenticationMethod = "none"
	ClientSecretBasic ClientAuthenticationMethod = "client_secret_basic"
	ClientSecretPost  ClientAuthenticationMethod = "client_secret_post"
)

type Config

type Config struct {
	Issuer                  string
	AuthorizationCodeTTL    time.Duration
	AccessTokenTTL          time.Duration
	RefreshTokenTTL         time.Duration
	RefreshTokenMaxLifetime time.Duration
	IDTokenTTL              time.Duration
	Store                   Store
	Users                   UserResolver
	Signer                  SigningKeyProvider
	Now                     func() time.Time
	AllowInsecureIssuer     bool
	Random                  io.Reader
	SupportedScopes         []string
}
type Consent struct {
	UserID   string
	ClientID string
	Scopes   []string
}

type DiscoveryMetadata

type DiscoveryMetadata struct {
	Issuer                            string   `json:"issuer"`
	AuthorizationEndpoint             string   `json:"authorization_endpoint"`
	TokenEndpoint                     string   `json:"token_endpoint"`
	UserinfoEndpoint                  string   `json:"userinfo_endpoint"`
	JWKSEndpoint                      string   `json:"jwks_uri"`
	RevocationEndpoint                string   `json:"revocation_endpoint"`
	ResponseTypesSupported            []string `json:"response_types_supported"`
	SubjectTypesSupported             []string `json:"subject_types_supported"`
	IDTokenSigningAlgValues           []string `json:"id_token_signing_alg_values_supported"`
	ScopesSupported                   []string `json:"scopes_supported"`
	ClaimsSupported                   []string `json:"claims_supported"`
	GrantTypesSupported               []string `json:"grant_types_supported"`
	CodeChallengeMethodsSupported     []string `json:"code_challenge_methods_supported"`
	TokenEndpointAuthMethods          []string `json:"token_endpoint_auth_methods_supported"`
	ResponseModesSupported            []string `json:"response_modes_supported"`
	AuthorizationResponseISSSupported bool     `json:"authorization_response_iss_parameter_supported"`
	RevocationEndpointAuthMethods     []string `json:"revocation_endpoint_auth_methods_supported"`
	RequestParameterSupported         bool     `json:"request_parameter_supported"`
	RequestURIParameterSupported      bool     `json:"request_uri_parameter_supported"`
	ClaimsParameterSupported          bool     `json:"claims_parameter_supported"`
}

DiscoveryMetadata is the OIDC discovery document before JSON encoding.

type IDTokenClaims

type IDTokenClaims struct {
	Issuer            string `json:"iss"`
	Subject           string `json:"sub"`
	Audience          string `json:"aud"`
	ExpiresAt         int64  `json:"exp"`
	IssuedAt          int64  `json:"iat"`
	AuthTime          int64  `json:"auth_time,omitempty"`
	Nonce             string `json:"nonce,omitempty"`
	Name              string `json:"name,omitempty"`
	PreferredUsername string `json:"preferred_username,omitempty"`
	Email             string `json:"email,omitempty"`
	EmailVerified     *bool  `json:"email_verified,omitempty"`
	Picture           string `json:"picture,omitempty"`
}

IDTokenClaims contains the claims emitted by the built-in code flow. The concrete type prevents adapters and signers from silently omitting required OpenID Connect claims.

func (IDTokenClaims) Validate

func (c IDTokenClaims) Validate() error

type IDTokenSigner

type IDTokenSigner interface {
	SignIDToken(context.Context, IDTokenClaims) (string, error)
}

type JWK

type JWK struct {
	KTY string `json:"kty"`
	Use string `json:"use,omitempty"`
	Alg string `json:"alg,omitempty"`
	Kid string `json:"kid"`
	N   string `json:"n,omitempty"`
	E   string `json:"e,omitempty"`
	X   string `json:"x,omitempty"`
	Y   string `json:"y,omitempty"`
}

JWK is the transport-neutral representation of a public signing key. N and E are base64url encoded for RSA keys; other key types may use X, Y, or a future extension field in the adapter.

type JWKSet

type JWKSet struct {
	Keys []JWK `json:"keys"`
}

type MemoryStore

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

MemoryStore is a concurrency-safe reference Store for tests and local development. Values are cloned at its boundary so callers cannot mutate internal state without holding the lock.

func NewMemoryStore

func NewMemoryStore() *MemoryStore

func (*MemoryStore) ExchangeAuthorizationCode

func (s *MemoryStore) ExchangeAuthorizationCode(_ context.Context, x AuthorizationCodeExchange) error

func (*MemoryStore) GetAccessToken

func (s *MemoryStore) GetAccessToken(_ context.Context, hash string) (*Token, error)

func (*MemoryStore) GetAuthorizationCode

func (s *MemoryStore) GetAuthorizationCode(_ context.Context, hash string) (*AuthorizationCode, error)

func (*MemoryStore) GetClient

func (s *MemoryStore) GetClient(_ context.Context, id string) (*Client, error)

func (*MemoryStore) GetConsent

func (s *MemoryStore) GetConsent(_ context.Context, userID, clientID string) (*Consent, error)

func (*MemoryStore) GetRefreshToken

func (s *MemoryStore) GetRefreshToken(_ context.Context, hash string) (*Token, error)

func (*MemoryStore) Purge

func (s *MemoryStore) Purge(_ context.Context, request PurgeRequest) (PurgeResult, error)

func (*MemoryStore) PutClient

func (s *MemoryStore) PutClient(c *Client)

func (*MemoryStore) RevokeAuthorizationCodeGrant

func (s *MemoryStore) RevokeAuthorizationCodeGrant(_ context.Context, codeHash string, now time.Time) error

func (*MemoryStore) RevokeGrant

func (s *MemoryStore) RevokeGrant(_ context.Context, userID, clientID string, now time.Time) error

func (*MemoryStore) RevokeToken

func (s *MemoryStore) RevokeToken(_ context.Context, hash, clientID string, now time.Time) error

func (*MemoryStore) RevokeTokenFamily

func (s *MemoryStore) RevokeTokenFamily(_ context.Context, family string, now time.Time) error

func (*MemoryStore) RotateRefreshToken

func (s *MemoryStore) RotateRefreshToken(_ context.Context, x RefreshTokenRotation) error

func (*MemoryStore) SaveAuthorizationCode

func (s *MemoryStore) SaveAuthorizationCode(_ context.Context, v *AuthorizationCode) error

func (*MemoryStore) SaveConsent

func (s *MemoryStore) SaveConsent(_ context.Context, v *Consent) error

type OAuthError

type OAuthError struct {
	Code            string
	Description     string
	URI             string
	Cause           error
	RedirectAllowed bool
	RedirectURI     string
	State           string
	ResponseMode    string
}

OAuthError is the protocol-level error returned by the core. An HTTP adapter can map Code to the OAuth error field and choose the appropriate status code without the core importing net/http.

func NewOAuthError

func NewOAuthError(code, description string) *OAuthError

func (*OAuthError) Error

func (e *OAuthError) Error() string

func (*OAuthError) Unwrap

func (e *OAuthError) Unwrap() error

type Provider

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

func New

func New(cfg Config) (*Provider, error)

func (*Provider) Authorize

func (p *Provider) Authorize(ctx context.Context, req AuthorizeRequest, auth Authentication, approved bool) (*AuthorizeResult, error)

func (*Provider) BeginAuthorization

func (p *Provider) BeginAuthorization(ctx context.Context, req AuthorizeRequest, auth Authentication) (*AuthorizationDecision, error)

BeginAuthorization validates an authorization request and tells the host application which user interaction is required. It never creates a code.

func (*Provider) ExchangeCode

func (p *Provider) ExchangeCode(ctx context.Context, req TokenRequest) (*TokenResponse, error)

func (*Provider) Metadata

func (p *Provider) Metadata() DiscoveryMetadata

Metadata returns the standard discovery document as typed data. The caller is responsible for JSON encoding it at the well-known HTTP endpoint.

func (*Provider) PublicJWKS

func (p *Provider) PublicJWKS(ctx context.Context) (JWKSet, error)

PublicJWKS returns the current public keys for the JWKS endpoint.

func (*Provider) Purge

func (p *Provider) Purge(ctx context.Context, revokedRetention time.Duration) (PurgeResult, error)

Purge removes terminal credentials without starting background goroutines. The host decides when to call it and how long revoked-token audit records are retained.

func (*Provider) Refresh

func (p *Provider) Refresh(ctx context.Context, req TokenRequest) (*TokenResponse, error)

func (*Provider) Revoke

func (p *Provider) Revoke(ctx context.Context, req TokenRevocationRequest) error

func (*Provider) RevokeGrant

func (p *Provider) RevokeGrant(ctx context.Context, userID, clientID string) error

RevokeGrant removes a user's consent and atomically revokes every access and refresh token belonging to that user/client grant.

func (*Provider) RevokeRefreshTokenFamily

func (p *Provider) RevokeRefreshTokenFamily(ctx context.Context, familyID string) error

RevokeRefreshTokenFamily revokes all refresh tokens produced by one rotation family, which is used when token reuse is detected.

func (*Provider) UserInfo

func (p *Provider) UserInfo(ctx context.Context, rawAccessToken string) (*UserInfoClaims, error)

UserInfo validates an opaque access token and resolves claims according to the scopes granted to that token.

func (*Provider) ValidateAccessToken

func (p *Provider) ValidateAccessToken(ctx context.Context, raw string) (*Token, error)

ValidateAccessToken resolves an opaque access token and enforces its expiration and revocation state. HTTP adapters can use the returned token to authorize UserInfo or resource requests.

type PublicKeyProvider

type PublicKeyProvider interface {
	PublicKeys(context.Context) ([]JWK, error)
}

PublicKeyProvider is optionally implemented by an IDTokenSigner. It keeps JWKS generation independent from a concrete RSA/ECDSA implementation.

type PurgeRequest

type PurgeRequest struct {
	Now           time.Time
	RevokedBefore time.Time
}

type PurgeResult

type PurgeResult struct {
	AuthorizationCodes int
	AccessTokens       int
	RefreshTokens      int
}

type RSAKeySet

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

RSAKeySet signs ID tokens with its active RS256 key and publishes every key retained for verification. Retain old keys until all tokens they signed have expired.

func GenerateRSAKeySet

func GenerateRSAKeySet(kid string, bits int) (*RSAKeySet, error)

func NewRSAKeySet

func NewRSAKeySet(kid string, key *rsa.PrivateKey) (*RSAKeySet, error)

func (*RSAKeySet) Add

func (s *RSAKeySet) Add(kid string, key *rsa.PrivateKey, active bool) error

Add installs a verification key and optionally makes it active for signing.

func (*RSAKeySet) AddVerificationKey

func (s *RSAKeySet) AddVerificationKey(kid string, key *rsa.PublicKey) error

AddVerificationKey retains a public key for validating tokens signed before rotation without retaining the corresponding private key.

func (*RSAKeySet) Prune

func (s *RSAKeySet) Prune(now time.Time) []string

Prune removes verification keys whose retirement time has arrived.

func (*RSAKeySet) PublicKeys

func (s *RSAKeySet) PublicKeys(context.Context) ([]JWK, error)

func (*RSAKeySet) Remove

func (s *RSAKeySet) Remove(kid string) error

Remove removes an old verification key. The active signing key cannot be removed until another key has been activated.

func (*RSAKeySet) Retire

func (s *RSAKeySet) Retire(kid string, at time.Time) error

Retire schedules a non-active verification key for removal after every ID token signed by it has expired.

func (*RSAKeySet) SignIDToken

func (s *RSAKeySet) SignIDToken(_ context.Context, claims IDTokenClaims) (string, error)

type RefreshTokenRotation

type RefreshTokenRotation struct {
	OldHash      string
	ClientID     string
	Now          time.Time
	AccessToken  *Token
	RefreshToken *Token
}

RefreshTokenRotation describes an atomic refresh-token rotation. A Store must revoke the complete family if OldHash has already been consumed.

type SigningKeyProvider

type SigningKeyProvider interface {
	IDTokenSigner
	PublicKeyProvider
}

type Store

type Store interface {
	GetClient(context.Context, string) (*Client, error)
	GetConsent(context.Context, string, string) (*Consent, error)
	SaveConsent(context.Context, *Consent) error
	SaveAuthorizationCode(context.Context, *AuthorizationCode) error
	GetAuthorizationCode(context.Context, string) (*AuthorizationCode, error)
	ExchangeAuthorizationCode(context.Context, AuthorizationCodeExchange) error
	GetAccessToken(context.Context, string) (*Token, error)
	GetRefreshToken(context.Context, string) (*Token, error)
	RotateRefreshToken(context.Context, RefreshTokenRotation) error
	RevokeToken(context.Context, string, string, time.Time) error
	RevokeTokenFamily(context.Context, string, time.Time) error
	RevokeGrant(context.Context, string, string, time.Time) error
	RevokeAuthorizationCodeGrant(context.Context, string, time.Time) error
	Purge(context.Context, PurgeRequest) (PurgeResult, error)
}

Store is the persistence boundary for the provider. ExchangeAuthorizationCode and RotateRefreshToken are transaction boundaries: either all changes are committed or none are.

type Token

type Token struct {
	Hash            string
	GrantID         string
	FamilyID        string
	UserID          string
	ClientID        string
	Scopes          []string
	ExpiresAt       time.Time
	FamilyExpiresAt time.Time
	RevokedAt       *time.Time
	AuthTime        time.Time
}

type TokenRequest

type TokenRequest struct {
	GrantType    string
	Code         string
	RefreshToken string
	ClientID     string
	ClientSecret string
	AuthMethod   ClientAuthenticationMethod
	RedirectURI  string
	CodeVerifier string
	Scope        []string
}

type TokenResponse

type TokenResponse struct {
	AccessToken  string
	TokenType    string
	ExpiresIn    int64
	IDToken      string
	RefreshToken string
	Scope        []string
}

type TokenRevocationRequest

type TokenRevocationRequest struct {
	Token         string
	ClientID      string
	ClientSecret  string
	AuthMethod    ClientAuthenticationMethod
	TokenTypeHint string
}

type User

type User struct {
	Subject           string
	Name              string
	PreferredUsername string
	Email             string
	EmailVerified     bool
	Picture           string
}

type UserInfoClaims

type UserInfoClaims struct {
	Subject           string `json:"sub"`
	Name              string `json:"name,omitempty"`
	PreferredUsername string `json:"preferred_username,omitempty"`
	Email             string `json:"email,omitempty"`
	EmailVerified     *bool  `json:"email_verified,omitempty"`
	Picture           string `json:"picture,omitempty"`
}

UserInfoClaims is the typed result for an OIDC UserInfo response.

type UserResolver

type UserResolver interface {
	ResolveUser(context.Context, string) (*User, error)
}

Directories

Path Synopsis
Package storetest provides a reusable contract suite for oidcprovider Store implementations.
Package storetest provides a reusable contract suite for oidcprovider Store implementations.

Jump to

Keyboard shortcuts

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