Documentation
¶
Overview ¶
Package oauth provides OAuth 2.0 and OpenID Connect (OIDC) authentication.
The package supports multiple OAuth 2.0 flows and token validation methods, with pre-configured providers for common identity services.
Supported Flows ¶
- Token Validation: Validate existing access tokens (JWT or introspection)
- Client Credentials: Machine-to-machine authentication
- Resource Owner Password: Direct username/password authentication
- Authorization Code: User-interactive flow with PKCE support
Token Validation ¶
Tokens can be validated using JWT (local validation with JWKS) or OAuth introspection (remote validation). Hybrid mode tries JWT first and falls back to introspection.
Example - Token Validation:
config := &oauth.Config{
Provider: oauth.Google(),
Flow: oauth.FlowTokenValidation,
ClientID: "your-client-id",
Validation: oauth.TokenValidationConfig{
Method: oauth.ValidationJWT,
JWKSURL: "https://www.googleapis.com/oauth2/v3/certs",
Issuer: "https://accounts.google.com",
Audience: "your-client-id",
},
Cache: oauth.CacheConfig{
Enabled: true,
MaxSize: 1000,
TTL: 5 * time.Minute,
},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
defer auth.Close()
claims, err := auth.ValidateToken(context.Background(), accessToken)
if err != nil {
log.Printf("Token validation failed: %v", err)
return
}
fmt.Printf("User: %s (%s)\n", claims.Name, claims.Email)
Client Credentials Flow ¶
Example - Client Credentials:
config := &oauth.Config{
Provider: oauth.Keycloak("https://keycloak.example.com", "master"),
Flow: oauth.FlowClientCredentials,
ClientID: "service-account",
ClientSecret: "secret",
Scopes: []string{"api.read", "api.write"},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
token, err := auth.AuthenticateClientCredentials(context.Background())
if err != nil {
log.Printf("Authentication failed: %v", err)
return
}
fmt.Printf("Access Token: %s\n", token.AccessToken)
fmt.Printf("Expires: %s\n", token.Expiry)
Password Flow ¶
Example - Resource Owner Password:
config := &oauth.Config{
Provider: oauth.Auth0("myapp.us.auth0.com"),
Flow: oauth.FlowPassword,
ClientID: "client-id",
ClientSecret: "client-secret",
Scopes: []string{"openid", "profile", "email"},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
token, err := auth.AuthenticatePassword(context.Background(), "[email protected]", "password")
if err != nil {
log.Printf("Authentication failed: %v", err)
return
}
fmt.Printf("Access Token: %s\n", token.AccessToken)
Authorization Code Flow ¶
Example - Authorization Code with PKCE:
config := &oauth.Config{
Provider: oauth.Microsoft(),
Flow: oauth.FlowAuthorizationCode,
ClientID: "client-id",
RedirectURL: "http://localhost:8080/callback",
Scopes: []string{"openid", "profile", "email"},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
// Generate authorization URL
state := generateRandomState() // Your CSRF token
authURL, codeVerifier, err := auth.BuildAuthURL(state, true, nil)
if err != nil {
log.Fatal(err)
}
// Redirect user to authURL...
// After callback with authorization code:
token, err := auth.ExchangeAuthorizationCode(context.Background(), code, codeVerifier)
if err != nil {
log.Printf("Token exchange failed: %v", err)
return
}
fmt.Printf("Access Token: %s\n", token.AccessToken)
fmt.Printf("ID Token: %s\n", token.IDToken)
Pre-configured Providers ¶
The package includes pre-configured providers for:
- Google() - Google OAuth
- Microsoft() - Microsoft Azure AD
- GitHub() - GitHub OAuth
- Okta(domain) - Okta
- Auth0(domain) - Auth0
- Keycloak(baseURL, realm) - Keycloak
Custom Providers ¶
For custom OAuth providers, use CustomProvider:
provider, err := oauth.CustomProvider(oauth.ProviderConfig{
ProviderName: "custom",
AuthEndpoint: "https://provider.com/oauth/authorize",
TokenEndpoint: "https://provider.com/oauth/token",
JWKSEndpoint: "https://provider.com/oauth/jwks",
IntrospectionEndpoint: "https://provider.com/oauth/introspect",
IssuerURL: "https://provider.com",
})
Token Caching ¶
The package includes an in-memory LRU cache for validated token claims. This reduces latency and load on the OAuth provider:
Cache: oauth.CacheConfig{
Enabled: true,
MaxSize: 1000, // Maximum cached tokens
TTL: 5 * time.Minute, // Cache duration
}
Thread Safety ¶
The Authenticator is thread-safe and can be used concurrently. It is immutable after construction and safe to share across goroutines.
Security Considerations ¶
- Always use TLS in production (enabled by default)
- Use PKCE for authorization code flow
- Validate issuer and audience claims
- Set appropriate clock skew tolerance
- Never log client secrets or tokens
- Use state parameter for CSRF protection
Integration with go-auth API ¶
The Authenticator implements the passwordAuthenticator interface and can be used with the api package:
import "github.com/jeremyhahn/go-auth/pkg/api"
oauthAuth, _ := oauth.NewAuthenticator(config)
service, _ := api.NewService(api.Config{
Backends: []api.Backend{
{Name: api.BackendOAuth, Handler: api.OAuth(oauthAuth)},
},
})
Index ¶
- Variables
- type AddressClaim
- type Authenticator
- func (a *Authenticator) Authenticate(ctx context.Context, username, token string) error
- func (a *Authenticator) AuthenticateClientCredentials(ctx context.Context) (*Token, error)
- func (a *Authenticator) AuthenticatePassword(ctx context.Context, username, password string) (*Token, error)
- func (a *Authenticator) BuildAuthURL(state string, usePKCE bool, additionalParams map[string]string) (authURL string, codeVerifier string, err error)
- func (a *Authenticator) ClearCache()
- func (a *Authenticator) ClearUserInfoCache()
- func (a *Authenticator) Close() error
- func (a *Authenticator) ExchangeAuthorizationCode(ctx context.Context, code, codeVerifier string) (*Token, error)
- func (a *Authenticator) GenerateNonce() (string, error)
- func (a *Authenticator) GetDiscovery(ctx context.Context) (*OIDCDiscoveryConfig, error)
- func (a *Authenticator) GetIdentityClaims(ctx context.Context, token *Token, nonce string) (*IdentityClaims, error)
- func (a *Authenticator) GetUserInfo(ctx context.Context, accessToken string) (*UserInfo, error)
- func (a *Authenticator) RefreshDiscovery(ctx context.Context) error
- func (a *Authenticator) RefreshToken(ctx context.Context, refreshToken string) (*Token, error)
- func (a *Authenticator) ValidateIDToken(ctx context.Context, idToken string, nonce string, accessToken string) (*IDTokenClaims, error)
- func (a *Authenticator) ValidateToken(ctx context.Context, token string) (*TokenClaims, error)
- type CacheConfig
- type Config
- type FlowType
- type HTTPClient
- type IDTokenClaims
- type IdentityClaims
- type OIDCConfig
- type OIDCDiscoveryConfig
- type Provider
- type ProviderConfig
- type Token
- type TokenCache
- type TokenClaims
- type TokenValidationConfig
- type UserInfo
- type UserInfoConfig
- type ValidationMethod
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrMissingToken indicates no token was provided for validation. ErrMissingToken = errors.New("oauth: missing token") // ErrInvalidToken indicates the token is malformed or has an invalid signature. ErrInvalidToken = errors.New("oauth: invalid token") // ErrExpiredToken indicates the token has expired. ErrExpiredToken = errors.New("oauth: token expired") // ErrInvalidConfiguration indicates the authenticator configuration is invalid. ErrInvalidConfiguration = errors.New("oauth: invalid configuration") // ErrProviderNotSupported indicates the requested provider is not supported. ErrProviderNotSupported = errors.New("oauth: provider not supported") // ErrFlowNotSupported indicates the requested OAuth flow is not supported. ErrFlowNotSupported = errors.New("oauth: flow not supported") // ErrInvalidClaims indicates the token claims are invalid or missing required fields. ErrInvalidClaims = errors.New("oauth: invalid claims") // ErrIntrospectionFailed indicates token introspection failed. ErrIntrospectionFailed = errors.New("oauth: introspection failed") // ErrJWKSFetchFailed indicates JWKS retrieval failed. ErrJWKSFetchFailed = errors.New("oauth: jwks fetch failed") // ErrTokenExchangeFailed indicates OAuth token exchange failed. ErrTokenExchangeFailed = errors.New("oauth: token exchange failed") // ErrOIDCNotEnabled indicates OIDC functionality is not enabled. ErrOIDCNotEnabled = errors.New("oauth: oidc not enabled") // ErrOIDCDiscoveryFailed indicates OIDC discovery document fetch failed. ErrOIDCDiscoveryFailed = errors.New("oauth: oidc discovery failed") // ErrOIDCInvalidDiscovery indicates the OIDC discovery document is invalid or incomplete. ErrOIDCInvalidDiscovery = errors.New("oauth: invalid oidc discovery document") // ErrOIDCMissingIDToken indicates no ID token was returned when one was required. ErrOIDCMissingIDToken = errors.New("oauth: missing id token") // ErrOIDCInvalidIDToken indicates the ID token is invalid or failed validation. ErrOIDCInvalidIDToken = errors.New("oauth: invalid id token") // ErrOIDCInvalidNonce indicates nonce validation failed. ErrOIDCInvalidNonce = errors.New("oauth: invalid nonce") // ErrOIDCNonceExpired indicates the nonce has expired. ErrOIDCNonceExpired = errors.New("oauth: nonce expired") // ErrOIDCNonceNotFound indicates the nonce was not found in the store. ErrOIDCNonceNotFound = errors.New("oauth: nonce not found") // ErrOIDCInvalidAtHash indicates at_hash validation failed. ErrOIDCInvalidAtHash = errors.New("oauth: invalid at_hash") // ErrOIDCAuthTimeTooOld indicates the auth_time is older than max_age. ErrOIDCAuthTimeTooOld = errors.New("oauth: authentication too old") // ErrOIDCInvalidACR indicates the acr claim doesn't match required values. ErrOIDCInvalidACR = errors.New("oauth: invalid acr") // ErrOIDCUserInfoFailed indicates UserInfo endpoint request failed. ErrOIDCUserInfoFailed = errors.New("oauth: userinfo request failed") // ErrOIDCInvalidUserInfo indicates UserInfo response is invalid. ErrOIDCInvalidUserInfo = errors.New("oauth: invalid userinfo response") )
Functions ¶
This section is empty.
Types ¶
type AddressClaim ¶
type AddressClaim struct {
Formatted string `json:"formatted,omitempty"`
StreetAddress string `json:"street_address,omitempty"`
Locality string `json:"locality,omitempty"`
Region string `json:"region,omitempty"`
PostalCode string `json:"postal_code,omitempty"`
Country string `json:"country,omitempty"`
}
AddressClaim represents the structured address claim.
type Authenticator ¶
type Authenticator struct {
// contains filtered or unexported fields
}
Authenticator is the main OAuth 2.0 authentication handler. It is thread-safe and immutable after construction.
func NewAuthenticator ¶
func NewAuthenticator(config *Config) (*Authenticator, error)
NewAuthenticator creates a new OAuth authenticator with the given configuration.
Example (AuthorizationCode) ¶
package main
import (
"fmt"
"log"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
config := &oauth.Config{
Provider: oauth.Microsoft(),
Flow: oauth.FlowAuthorizationCode,
ClientID: "client-id",
RedirectURL: "http://localhost:8080/callback",
Scopes: []string{"openid", "profile", "email"},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
// Generate authorization URL with PKCE
state := "random-state-string"
authURL, codeVerifier, err := auth.BuildAuthURL(state, true, nil)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Authorization URL generated: %v\n", authURL != "")
fmt.Printf("Code verifier generated: %v\n", codeVerifier != "")
// After receiving callback with code:
// token, err := auth.ExchangeAuthorizationCode(context.Background(), code, codeVerifier)
}
Example (ClientCredentials) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
config := &oauth.Config{
Provider: oauth.Keycloak("https://keycloak.example.com", "master"),
Flow: oauth.FlowClientCredentials,
ClientID: "service-account",
ClientSecret: "secret",
Scopes: []string{"api.read", "api.write"},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
token, err := auth.AuthenticateClientCredentials(context.Background())
if err != nil {
log.Printf("Authentication failed: %v", err)
return
}
fmt.Printf("Token Type: %s\n", token.TokenType)
}
Example (Password) ¶
package main
import (
"context"
"fmt"
"log"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
config := &oauth.Config{
Provider: oauth.Auth0("myapp.us.auth0.com"),
Flow: oauth.FlowPassword,
ClientID: "client-id",
ClientSecret: "client-secret",
Scopes: []string{"openid", "profile", "email"},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
token, err := auth.AuthenticatePassword(context.Background(), "[email protected]", "password")
if err != nil {
log.Printf("Authentication failed: %v", err)
return
}
fmt.Printf("Access Token received: %v\n", token.AccessToken != "")
}
Example (TokenValidation) ¶
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
config := &oauth.Config{
Provider: oauth.Google(),
Flow: oauth.FlowTokenValidation,
ClientID: "your-client-id",
Validation: oauth.TokenValidationConfig{
Method: oauth.ValidationJWT,
JWKSURL: "https://www.googleapis.com/oauth2/v3/certs",
Issuer: "https://accounts.google.com",
Audience: "your-client-id",
},
Cache: oauth.CacheConfig{
Enabled: true,
MaxSize: 1000,
TTL: 5 * time.Minute,
},
}
auth, err := oauth.NewAuthenticator(config)
if err != nil {
log.Fatal(err)
}
defer auth.Close()
// Validate token
claims, err := auth.ValidateToken(context.Background(), "access-token")
if err != nil {
log.Printf("Token validation failed: %v", err)
return
}
fmt.Printf("User: %s\n", claims.Subject)
}
func (*Authenticator) Authenticate ¶
func (a *Authenticator) Authenticate(ctx context.Context, username, token string) error
Authenticate is a convenience method that validates a token. It implements the passwordAuthenticator interface used by the api package. The token should be passed as the password parameter.
func (*Authenticator) AuthenticateClientCredentials ¶
func (a *Authenticator) AuthenticateClientCredentials(ctx context.Context) (*Token, error)
AuthenticateClientCredentials performs client credentials flow. Returns a Token on successful authentication.
func (*Authenticator) AuthenticatePassword ¶
func (a *Authenticator) AuthenticatePassword(ctx context.Context, username, password string) (*Token, error)
AuthenticatePassword performs resource owner password credentials flow. Returns a Token on successful authentication.
func (*Authenticator) BuildAuthURL ¶
func (a *Authenticator) BuildAuthURL(state string, usePKCE bool, additionalParams map[string]string) (authURL string, codeVerifier string, err error)
BuildAuthURL builds the authorization URL for the authorization code flow. state should be a random string to prevent CSRF attacks. usePKCE enables PKCE (Proof Key for Code Exchange) and returns the code verifier.
func (*Authenticator) ClearCache ¶
func (a *Authenticator) ClearCache()
ClearCache clears all cached tokens.
func (*Authenticator) ClearUserInfoCache ¶
func (a *Authenticator) ClearUserInfoCache()
ClearUserInfoCache clears the UserInfo response cache.
func (*Authenticator) Close ¶
func (a *Authenticator) Close() error
Close releases resources held by the authenticator.
func (*Authenticator) ExchangeAuthorizationCode ¶
func (a *Authenticator) ExchangeAuthorizationCode(ctx context.Context, code, codeVerifier string) (*Token, error)
ExchangeAuthorizationCode exchanges an authorization code for tokens. codeVerifier is optional and only required if PKCE was used.
func (*Authenticator) GenerateNonce ¶
func (a *Authenticator) GenerateNonce() (string, error)
GenerateNonce generates a cryptographically random nonce for OIDC authorization requests. The nonce should be stored and validated when the ID token is received.
func (*Authenticator) GetDiscovery ¶
func (a *Authenticator) GetDiscovery(ctx context.Context) (*OIDCDiscoveryConfig, error)
GetDiscovery retrieves the OIDC discovery document for the configured issuer. This can be useful for inspecting provider capabilities.
func (*Authenticator) GetIdentityClaims ¶
func (a *Authenticator) GetIdentityClaims(ctx context.Context, token *Token, nonce string) (*IdentityClaims, error)
GetIdentityClaims retrieves complete identity information by merging ID token and UserInfo. This is a convenience method that validates the ID token and optionally fetches UserInfo.
func (*Authenticator) GetUserInfo ¶
GetUserInfo fetches user information from the OIDC UserInfo endpoint. Requires an access token with the appropriate scopes (typically "openid" and "profile").
func (*Authenticator) RefreshDiscovery ¶
func (a *Authenticator) RefreshDiscovery(ctx context.Context) error
RefreshDiscovery forces a refresh of the cached OIDC discovery document.
func (*Authenticator) RefreshToken ¶
RefreshToken uses a refresh token to obtain a new access token.
func (*Authenticator) ValidateIDToken ¶
func (a *Authenticator) ValidateIDToken(ctx context.Context, idToken string, nonce string, accessToken string) (*IDTokenClaims, error)
ValidateIDToken validates an OpenID Connect ID token. nonce is optional but recommended for authorization code flow. accessToken is optional and used for at_hash validation if present.
func (*Authenticator) ValidateToken ¶
func (a *Authenticator) ValidateToken(ctx context.Context, token string) (*TokenClaims, error)
ValidateToken validates an access token and returns the claims. The token can be a JWT or opaque token depending on the provider.
type CacheConfig ¶
type CacheConfig struct {
// Enabled determines if caching is active.
Enabled bool
// MaxSize is the maximum number of tokens to cache (LRU eviction).
MaxSize int
// TTL is how long to cache valid tokens.
TTL time.Duration
}
CacheConfig contains settings for token caching.
type Config ¶
type Config struct {
// Provider is the OAuth provider configuration.
Provider Provider
// Flow determines which OAuth flow to use.
Flow FlowType
// ClientID is the OAuth client identifier.
ClientID string
// ClientSecret is the OAuth client secret (required for some flows).
ClientSecret string
// Scopes are the OAuth scopes to request.
Scopes []string
// RedirectURL is the callback URL for authorization code flow.
RedirectURL string
// Validation contains token validation settings.
Validation TokenValidationConfig
// Cache contains token caching settings.
Cache CacheConfig
// OIDC contains OpenID Connect specific configuration.
// When nil or OIDC.Enabled=false, operates in pure OAuth 2.0 mode.
// This is fully backward compatible - existing OAuth-only code is unaffected.
OIDC *OIDCConfig
// Timeout is the HTTP client timeout for OAuth requests.
Timeout time.Duration
// TLSConfig allows custom TLS configuration.
TLSConfig *tls.Config
// InsecureSkipVerify disables TLS certificate verification (not recommended).
InsecureSkipVerify bool
}
Config contains the complete OAuth authenticator configuration.
type FlowType ¶
type FlowType string
FlowType identifies the OAuth 2.0 flow to use.
const ( // FlowTokenValidation validates existing tokens without issuing new ones. FlowTokenValidation FlowType = "token_validation" // FlowClientCredentials uses OAuth 2.0 client credentials flow. FlowClientCredentials FlowType = "client_credentials" // FlowPassword uses OAuth 2.0 resource owner password credentials flow. FlowPassword FlowType = "password" // FlowAuthorizationCode uses OAuth 2.0 authorization code flow with PKCE. FlowAuthorizationCode FlowType = "authorization_code" )
type HTTPClient ¶
HTTPClient defines the interface for making HTTP requests. This abstraction allows for testing and custom implementations.
type IDTokenClaims ¶
type IDTokenClaims struct {
// Standard JWT claims
Issuer string `json:"iss"`
Subject string `json:"sub"`
Audience []string `json:"aud"`
ExpiresAt int64 `json:"exp"`
IssuedAt int64 `json:"iat"`
NotBefore int64 `json:"nbf,omitempty"`
// OIDC-specific claims
AuthTime int64 `json:"auth_time,omitempty"`
Nonce string `json:"nonce,omitempty"`
ACR string `json:"acr,omitempty"`
AMR []string `json:"amr,omitempty"`
AZP string `json:"azp,omitempty"`
// Hash claims for validation
AtHash string `json:"at_hash,omitempty"`
CHash string `json:"c_hash,omitempty"`
// Profile claims
Name string `json:"name,omitempty"`
GivenName string `json:"given_name,omitempty"`
FamilyName string `json:"family_name,omitempty"`
MiddleName string `json:"middle_name,omitempty"`
Nickname string `json:"nickname,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty"`
Profile string `json:"profile,omitempty"`
Picture string `json:"picture,omitempty"`
Website string `json:"website,omitempty"`
Gender string `json:"gender,omitempty"`
Birthdate string `json:"birthdate,omitempty"`
Zoneinfo string `json:"zoneinfo,omitempty"`
Locale string `json:"locale,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
// Email claims
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
// Phone claims
PhoneNumber string `json:"phone_number,omitempty"`
PhoneNumberVerified bool `json:"phone_number_verified,omitempty"`
// Address claim (structured)
Address *AddressClaim `json:"address,omitempty"`
// Custom claims
Custom map[string]interface{} `json:"-"`
}
IDTokenClaims represents the standard OpenID Connect ID token claims.
type IdentityClaims ¶
type IdentityClaims struct {
// Identity
Subject string
PreferredUsername string
// Profile
Name string
GivenName string
FamilyName string
MiddleName string
Nickname string
Profile string
Picture string
Website string
Gender string
Birthdate string
Zoneinfo string
Locale string
UpdatedAt time.Time
// Email
Email string
EmailVerified bool
// Phone
PhoneNumber string
PhoneNumberVerified bool
// Address
Address *AddressClaim
// Authentication metadata
AuthTime time.Time
ACR string
AMR []string
Issuer string
IssuedAt time.Time
ExpiresAt time.Time
// Custom claims from both ID token and UserInfo
Custom map[string]interface{}
}
IdentityClaims represents the merged identity information from ID token and UserInfo.
func MergeIdentityClaims ¶
func MergeIdentityClaims(idToken *IDTokenClaims, userInfo *UserInfo) *IdentityClaims
MergeIdentityClaims creates IdentityClaims by merging ID token and UserInfo claims. UserInfo claims take precedence for profile data, but authentication metadata comes from ID token.
type OIDCConfig ¶
type OIDCConfig struct {
// Enabled determines if OIDC features are active.
Enabled bool
// DiscoveryURL is the OIDC discovery endpoint URL.
// If empty, will attempt to construct from Issuer + "/.well-known/openid-configuration"
DiscoveryURL string
// SkipDiscovery disables automatic discovery and uses manually configured endpoints.
SkipDiscovery bool
// Discovery contains cached discovery configuration (populated automatically).
Discovery *OIDCDiscoveryConfig
// DiscoveryCacheTTL determines how long to cache discovery documents.
// Default: 24 hours
DiscoveryCacheTTL time.Duration
// ValidateNonce enables nonce validation for ID tokens (recommended).
ValidateNonce bool
// NonceLifetime determines how long nonces are valid.
// Default: 10 minutes
NonceLifetime time.Duration
// RequireIDToken causes token exchanges to fail if no ID token is returned.
RequireIDToken bool
// ValidateAtHash enables at_hash validation in ID tokens.
ValidateAtHash bool
// MaxAge is the maximum authentication age in seconds.
// If set and auth_time + max_age < now, authentication is considered stale.
MaxAge int
// ACRValues are the Authentication Context Class References to request.
ACRValues []string
// RequireACR causes validation to fail if the acr claim doesn't match ACRValues.
RequireACR bool
// UserInfoConfig contains settings for UserInfo endpoint calls.
UserInfo UserInfoConfig
}
OIDCConfig contains OpenID Connect specific configuration. When nil or Enabled=false, the authenticator operates in pure OAuth 2.0 mode.
func DefaultOIDCConfig ¶
func DefaultOIDCConfig() *OIDCConfig
DefaultOIDCConfig returns an OIDCConfig with sensible defaults.
type OIDCDiscoveryConfig ¶
type OIDCDiscoveryConfig struct {
// Issuer is the OIDC issuer identifier.
Issuer string `json:"issuer"`
// AuthorizationEndpoint is the authorization endpoint URL.
AuthorizationEndpoint string `json:"authorization_endpoint"`
// TokenEndpoint is the token endpoint URL.
TokenEndpoint string `json:"token_endpoint"`
// UserInfoEndpoint is the UserInfo endpoint URL.
UserInfoEndpoint string `json:"userinfo_endpoint"`
// JWKSUri is the JWKS endpoint URL.
JWKSUri string `json:"jwks_uri"`
// RegistrationEndpoint is the client registration endpoint URL.
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
// ScopesSupported lists supported OAuth 2.0 scopes.
ScopesSupported []string `json:"scopes_supported,omitempty"`
// ResponseTypesSupported lists supported OAuth 2.0 response types.
ResponseTypesSupported []string `json:"response_types_supported"`
// ResponseModesSupported lists supported OAuth 2.0 response modes.
ResponseModesSupported []string `json:"response_modes_supported,omitempty"`
// GrantTypesSupported lists supported OAuth 2.0 grant types.
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
// ACRValuesSupported lists supported Authentication Context Class References.
ACRValuesSupported []string `json:"acr_values_supported,omitempty"`
// SubjectTypesSupported lists supported subject identifier types.
SubjectTypesSupported []string `json:"subject_types_supported"`
// IDTokenSigningAlgValuesSupported lists supported signing algorithms for ID tokens.
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
// IDTokenEncryptionAlgValuesSupported lists supported encryption algorithms for ID tokens.
IDTokenEncryptionAlgValuesSupported []string `json:"id_token_encryption_alg_values_supported,omitempty"`
// IDTokenEncryptionEncValuesSupported lists supported encryption encoding methods for ID tokens.
IDTokenEncryptionEncValuesSupported []string `json:"id_token_encryption_enc_values_supported,omitempty"`
// UserInfoSigningAlgValuesSupported lists supported signing algorithms for UserInfo.
UserInfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported,omitempty"`
// UserInfoEncryptionAlgValuesSupported lists supported encryption algorithms for UserInfo.
UserInfoEncryptionAlgValuesSupported []string `json:"userinfo_encryption_alg_values_supported,omitempty"`
// UserInfoEncryptionEncValuesSupported lists supported encryption encoding methods for UserInfo.
UserInfoEncryptionEncValuesSupported []string `json:"userinfo_encryption_enc_values_supported,omitempty"`
// TokenEndpointAuthMethodsSupported lists supported client authentication methods.
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
// ClaimsSupported lists supported claim names.
ClaimsSupported []string `json:"claims_supported,omitempty"`
// CodeChallengeMethodsSupported lists supported PKCE challenge methods.
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
// IntrospectionEndpoint is the token introspection endpoint URL.
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
// RevocationEndpoint is the token revocation endpoint URL.
RevocationEndpoint string `json:"revocation_endpoint,omitempty"`
// EndSessionEndpoint is the logout endpoint URL.
EndSessionEndpoint string `json:"end_session_endpoint,omitempty"`
// FetchedAt tracks when this discovery document was retrieved.
FetchedAt time.Time `json:"-"`
}
OIDCDiscoveryConfig represents an OIDC discovery document. Based on OpenID Connect Discovery 1.0 specification.
func (*OIDCDiscoveryConfig) Expired ¶
func (d *OIDCDiscoveryConfig) Expired(ttl time.Duration) bool
Expired returns true if the discovery document should be refreshed.
func (*OIDCDiscoveryConfig) Validate ¶
func (d *OIDCDiscoveryConfig) Validate() error
Validate checks if the discovery document contains required fields.
type Provider ¶
type Provider interface {
// Name returns the provider's identifier.
Name() string
// AuthURL returns the authorization endpoint URL.
AuthURL() string
// TokenURL returns the token endpoint URL.
TokenURL() string
// JWKSURL returns the JWKS endpoint URL for JWT validation.
JWKSURL() string
// IntrospectionURL returns the token introspection endpoint URL (optional).
IntrospectionURL() string
// Issuer returns the expected token issuer.
Issuer() string
// UserInfoURL returns the OIDC UserInfo endpoint URL (optional).
// Returns empty string if the provider doesn't support OIDC UserInfo.
UserInfoURL() string
}
Provider defines the interface for OAuth 2.0 providers.
func Auth0 ¶
Auth0 returns a pre-configured Auth0 OAuth provider. domain should be your Auth0 domain (e.g., "myapp.us.auth0.com").
Example ¶
package main
import (
"fmt"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
provider := oauth.Auth0("myapp.us.auth0.com")
fmt.Println(provider.Name())
}
Output: auth0
func CustomProvider ¶
func CustomProvider(cfg ProviderConfig) (Provider, error)
CustomProvider creates a Provider from custom configuration.
func GitHub ¶
func GitHub() Provider
GitHub returns a pre-configured GitHub OAuth provider.
Example ¶
package main
import (
"fmt"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
provider := oauth.GitHub()
fmt.Println(provider.Name())
}
Output: github
func Google ¶
func Google() Provider
Google returns a pre-configured Google OAuth provider.
Example ¶
package main
import (
"fmt"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
provider := oauth.Google()
fmt.Println(provider.Name())
}
Output: google
func Keycloak ¶
Keycloak returns a pre-configured Keycloak OAuth provider. baseURL is your Keycloak server URL (e.g., "https://keycloak.example.com"). realm is the Keycloak realm name (e.g., "master").
Example ¶
package main
import (
"fmt"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
provider := oauth.Keycloak("https://keycloak.example.com", "master")
fmt.Println(provider.Name())
}
Output: keycloak
func Microsoft ¶
func Microsoft() Provider
Microsoft returns a pre-configured Microsoft OAuth provider (Azure AD v2).
Example ¶
package main
import (
"fmt"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
provider := oauth.Microsoft()
fmt.Println(provider.Name())
}
Output: microsoft
func Okta ¶
Okta returns a pre-configured Okta OAuth provider. domain should be your Okta domain (e.g., "dev-12345.okta.com").
Example ¶
package main
import (
"fmt"
"github.com/jeremyhahn/go-auth/pkg/oauth"
)
func main() {
provider := oauth.Okta("dev-12345.okta.com")
fmt.Println(provider.Name())
}
Output: okta
type ProviderConfig ¶
type ProviderConfig struct {
ProviderName string
AuthEndpoint string
TokenEndpoint string
JWKSEndpoint string
IntrospectionEndpoint string
IssuerURL string
UserInfoEndpoint string
}
ProviderConfig holds configuration for a custom OAuth provider.
type Token ¶
type Token struct {
// AccessToken is the OAuth access token.
AccessToken string
// TokenType is the type of token (usually "Bearer").
TokenType string
// RefreshToken is used to obtain new access tokens (optional).
RefreshToken string
// Expiry is when the access token expires.
Expiry time.Time
// Scopes are the scopes granted to this token.
Scopes []string
// IDToken is the OpenID Connect ID token (optional).
IDToken string
}
Token represents an OAuth 2.0 access token and associated metadata.
type TokenCache ¶
type TokenCache interface {
// Get retrieves a cached token claims by key.
// Returns nil if not found or expired.
Get(key string) *TokenClaims
// Set stores token claims with the specified TTL.
Set(key string, claims *TokenClaims, ttl time.Duration)
// Delete removes a token from the cache.
Delete(key string)
// Clear removes all cached tokens.
Clear()
}
TokenCache defines the interface for caching validated tokens.
type TokenClaims ¶
type TokenClaims struct {
// Subject is the subject identifier (typically user ID).
Subject string
// Issuer is the token issuer.
Issuer string
// Audience is the intended audience for this token.
Audience []string
// ExpiresAt is when the token expires.
ExpiresAt time.Time
// IssuedAt is when the token was issued.
IssuedAt time.Time
// NotBefore is the time before which the token is not valid.
NotBefore time.Time
// Scopes are the scopes granted to this token.
Scopes []string
// Email is the user's email address (if present in claims).
Email string
// EmailVerified indicates if the email is verified (OIDC).
EmailVerified bool
// Name is the user's display name (if present in claims).
Name string
// Groups are the user's group memberships (if present in claims).
Groups []string
// Custom contains any additional claims not mapped to standard fields.
Custom map[string]interface{}
}
TokenClaims represents validated claims extracted from a token.
func (*TokenClaims) Valid ¶
func (c *TokenClaims) Valid() bool
Valid returns true if the token claims are currently valid based on time.
func (*TokenClaims) ValidWithClockSkew ¶
func (c *TokenClaims) ValidWithClockSkew(skew time.Duration) bool
ValidWithClockSkew returns true if the claims are valid allowing for clock skew.
type TokenValidationConfig ¶
type TokenValidationConfig struct {
// Method determines how tokens are validated.
Method ValidationMethod
// JWKSURL is the URL to the provider's JWKS endpoint for JWT validation.
JWKSURL string
// IntrospectionURL is the URL to the OAuth introspection endpoint.
IntrospectionURL string
// Audience specifies the expected audience claim (optional).
Audience string
// Issuer specifies the expected issuer claim (optional).
Issuer string
// ClockSkew allows for clock drift between systems.
ClockSkew time.Duration
// RequiredClaims specifies claim names that must be present in the token.
RequiredClaims []string
}
TokenValidationConfig contains settings for token validation.
type UserInfo ¶
type UserInfo struct {
Subject string `json:"sub"`
Name string `json:"name,omitempty"`
GivenName string `json:"given_name,omitempty"`
FamilyName string `json:"family_name,omitempty"`
MiddleName string `json:"middle_name,omitempty"`
Nickname string `json:"nickname,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty"`
Profile string `json:"profile,omitempty"`
Picture string `json:"picture,omitempty"`
Website string `json:"website,omitempty"`
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
Gender string `json:"gender,omitempty"`
Birthdate string `json:"birthdate,omitempty"`
Zoneinfo string `json:"zoneinfo,omitempty"`
Locale string `json:"locale,omitempty"`
PhoneNumber string `json:"phone_number,omitempty"`
PhoneNumberVerified bool `json:"phone_number_verified,omitempty"`
Address *AddressClaim `json:"address,omitempty"`
UpdatedAt int64 `json:"updated_at,omitempty"`
Custom map[string]interface{} `json:"-"`
}
UserInfo represents claims from the OIDC UserInfo endpoint.
type UserInfoConfig ¶
type UserInfoConfig struct {
// Enabled determines if UserInfo endpoint should be called.
Enabled bool
// CacheTTL determines how long to cache UserInfo responses.
// Default: 5 minutes
CacheTTL time.Duration
// Timeout is the HTTP timeout for UserInfo requests.
// Default: 10 seconds
Timeout time.Duration
}
UserInfoConfig contains settings for UserInfo endpoint interactions.
type ValidationMethod ¶
type ValidationMethod string
ValidationMethod identifies how tokens should be validated.
const ( // ValidationJWT performs local JWT validation using JWKS. ValidationJWT ValidationMethod = "jwt" // ValidationIntrospection performs remote token introspection. ValidationIntrospection ValidationMethod = "introspection" // ValidationHybrid attempts JWT first, falls back to introspection. ValidationHybrid ValidationMethod = "hybrid" )