oauth

package
v0.0.0-...-fdb02f3 Latest Latest
Warning

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

Go to latest
Published: Nov 15, 2025 License: Apache-2.0 Imports: 21 Imported by: 0

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

Examples

Constants

This section is empty.

Variables

View Source
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

func (a *Authenticator) GetUserInfo(ctx context.Context, accessToken string) (*UserInfo, error)

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

func (a *Authenticator) RefreshToken(ctx context.Context, refreshToken string) (*Token, error)

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.

func (*Config) Validate

func (c *Config) Validate() error

Validate checks if the configuration is valid for the specified flow.

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

type HTTPClient interface {
	Do(req *http.Request) (*http.Response, error)
}

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

func Auth0(domain string) Provider

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

func Keycloak(baseURL, realm string) Provider

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

func Okta(domain string) Provider

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.

func (*Token) Expired

func (t *Token) Expired() bool

Expired returns true if the token has expired.

func (*Token) ExpiresIn

func (t *Token) ExpiresIn() time.Duration

ExpiresIn returns the duration until the token expires. Returns 0 if the token is already expired or has no expiry.

func (*Token) Valid

func (t *Token) Valid() bool

Valid returns true if the token is not expired.

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"
)

Jump to

Keyboard shortcuts

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