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 ¶
- Variables
- func GenerateClientSecret() (string, error)
- func HashClientSecret(secret string) string
- func MarshalRSAPrivateKeyPEM(key *rsa.PrivateKey) ([]byte, error)
- func ParseRSAPrivateKeyPEM(data []byte) (*rsa.PrivateKey, error)
- func ValidateClient(client Client) error
- type Authentication
- type AuthorizationAction
- type AuthorizationClient
- type AuthorizationCode
- type AuthorizationCodeExchange
- type AuthorizationDecision
- type AuthorizeRequest
- type AuthorizeResult
- type Client
- type ClientAuthenticationMethod
- type Config
- type Consent
- type DiscoveryMetadata
- type IDTokenClaims
- type IDTokenSigner
- type JWK
- type JWKSet
- type MemoryStore
- func (s *MemoryStore) ExchangeAuthorizationCode(_ context.Context, x AuthorizationCodeExchange) error
- func (s *MemoryStore) GetAccessToken(_ context.Context, hash string) (*Token, error)
- func (s *MemoryStore) GetAuthorizationCode(_ context.Context, hash string) (*AuthorizationCode, error)
- func (s *MemoryStore) GetClient(_ context.Context, id string) (*Client, error)
- func (s *MemoryStore) GetConsent(_ context.Context, userID, clientID string) (*Consent, error)
- func (s *MemoryStore) GetRefreshToken(_ context.Context, hash string) (*Token, error)
- func (s *MemoryStore) Purge(_ context.Context, request PurgeRequest) (PurgeResult, error)
- func (s *MemoryStore) PutClient(c *Client)
- func (s *MemoryStore) RevokeAuthorizationCodeGrant(_ context.Context, codeHash string, now time.Time) error
- func (s *MemoryStore) RevokeGrant(_ context.Context, userID, clientID string, now time.Time) error
- func (s *MemoryStore) RevokeToken(_ context.Context, hash, clientID string, now time.Time) error
- func (s *MemoryStore) RevokeTokenFamily(_ context.Context, family string, now time.Time) error
- func (s *MemoryStore) RotateRefreshToken(_ context.Context, x RefreshTokenRotation) error
- func (s *MemoryStore) SaveAuthorizationCode(_ context.Context, v *AuthorizationCode) error
- func (s *MemoryStore) SaveConsent(_ context.Context, v *Consent) error
- type OAuthError
- type Provider
- func (p *Provider) Authorize(ctx context.Context, req AuthorizeRequest, auth Authentication, approved bool) (*AuthorizeResult, error)
- func (p *Provider) BeginAuthorization(ctx context.Context, req AuthorizeRequest, auth Authentication) (*AuthorizationDecision, error)
- func (p *Provider) ExchangeCode(ctx context.Context, req TokenRequest) (*TokenResponse, error)
- func (p *Provider) Metadata() DiscoveryMetadata
- func (p *Provider) PublicJWKS(ctx context.Context) (JWKSet, error)
- func (p *Provider) Purge(ctx context.Context, revokedRetention time.Duration) (PurgeResult, error)
- func (p *Provider) Refresh(ctx context.Context, req TokenRequest) (*TokenResponse, error)
- func (p *Provider) Revoke(ctx context.Context, req TokenRevocationRequest) error
- func (p *Provider) RevokeGrant(ctx context.Context, userID, clientID string) error
- func (p *Provider) RevokeRefreshTokenFamily(ctx context.Context, familyID string) error
- func (p *Provider) UserInfo(ctx context.Context, rawAccessToken string) (*UserInfoClaims, error)
- func (p *Provider) ValidateAccessToken(ctx context.Context, raw string) (*Token, error)
- type PublicKeyProvider
- type PurgeRequest
- type PurgeResult
- type RSAKeySet
- func (s *RSAKeySet) Add(kid string, key *rsa.PrivateKey, active bool) error
- func (s *RSAKeySet) AddVerificationKey(kid string, key *rsa.PublicKey) error
- func (s *RSAKeySet) Prune(now time.Time) []string
- func (s *RSAKeySet) PublicKeys(context.Context) ([]JWK, error)
- func (s *RSAKeySet) Remove(kid string) error
- func (s *RSAKeySet) Retire(kid string, at time.Time) error
- func (s *RSAKeySet) SignIDToken(_ context.Context, claims IDTokenClaims) (string, error)
- type RefreshTokenRotation
- type SigningKeyProvider
- type Store
- type Token
- type TokenRequest
- type TokenResponse
- type TokenRevocationRequest
- type User
- type UserInfoClaims
- type UserResolver
Constants ¶
This section is empty.
Variables ¶
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") ErrAuthorizationCodeReplay = errors.New("authorization code replay") )
Functions ¶
func GenerateClientSecret ¶
GenerateClientSecret returns a 256-bit, URL-safe client secret.
func HashClientSecret ¶
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 ¶
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 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 AuthorizeResult ¶
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 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 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 (*MemoryStore) GetAuthorizationCode ¶
func (s *MemoryStore) GetAuthorizationCode(_ context.Context, hash string) (*AuthorizationCode, error)
func (*MemoryStore) GetConsent ¶
func (*MemoryStore) GetRefreshToken ¶
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 (*MemoryStore) RevokeGrant ¶
func (*MemoryStore) RevokeToken ¶
func (*MemoryStore) RevokeTokenFamily ¶
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 (*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 ¶
PublicJWKS returns the current public keys for the JWKS endpoint.
func (*Provider) Purge ¶
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 ¶
RevokeGrant removes a user's consent and atomically revokes every access and refresh token belonging to that user/client grant.
func (*Provider) RevokeRefreshTokenFamily ¶
RevokeRefreshTokenFamily revokes all refresh tokens produced by one rotation family, which is used when token reuse is detected.
func (*Provider) UserInfo ¶
UserInfo validates an opaque access token and resolves claims according to the scopes granted to that token.
func (*Provider) ValidateAccessToken ¶
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 ¶
PublicKeyProvider is optionally implemented by an IDTokenSigner. It keeps JWKS generation independent from a concrete RSA/ECDSA implementation.
type PurgeResult ¶
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 NewRSAKeySet ¶
func NewRSAKeySet(kid string, key *rsa.PrivateKey) (*RSAKeySet, error)
func (*RSAKeySet) AddVerificationKey ¶
AddVerificationKey retains a public key for validating tokens signed before rotation without retaining the corresponding private key.
func (*RSAKeySet) Remove ¶
Remove removes an old verification key. The active signing key cannot be removed until another key has been activated.
func (*RSAKeySet) Retire ¶
Retire schedules a non-active verification key for removal after every ID token signed by it has expired.
func (*RSAKeySet) SignIDToken ¶
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 TokenRequest ¶
type TokenResponse ¶
type TokenRevocationRequest ¶
type TokenRevocationRequest struct {
Token string
ClientID string
ClientSecret string
AuthMethod ClientAuthenticationMethod
TokenTypeHint 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.