upstream

package
v0.7.1 Latest Latest
Warning

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

Go to latest
Published: Jan 15, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package upstream provides types and implementations for upstream Identity Provider communication in the OAuth authorization server.

Architecture

The package is designed around a core Provider interface that abstracts upstream IDP operations. The interface captures essential OAuth/OIDC operations without leaking implementation details:

  • AuthorizationURL: Build redirect URL for user authentication
  • ExchangeCode: Exchange authorization code for tokens
  • RefreshTokens: Refresh expired tokens
  • UserInfo: Fetch user claims

Optional Capability Interfaces

Implementations may also implement optional capability interfaces for OIDC-specific features. Consumers should use type assertions to check:

if validator, ok := provider.(upstream.IDTokenNonceValidator); ok {
    claims, err := validator.ValidateIDTokenWithNonce(idToken, nonce)
}

Available optional interfaces:

  • IDTokenNonceValidator: OIDC nonce validation for replay protection
  • UserInfoSubjectValidator: OIDC subject validation per Section 5.3.4

Type Hierarchy

Provider (interface)
    |
OIDCProvider (implementation)
    |-- IDTokenNonceValidator (optional)
    +-- UserInfoSubjectValidator (optional)

Value Objects

  • Tokens: Token response from upstream IDP
  • UserInfo: User claims from UserInfo endpoint
  • Config: Configuration for upstream IDP connection
  • IDTokenClaims: Parsed claims from ID token

Usage

config := &upstream.Config{
    Issuer:       "https://accounts.google.com",
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    RedirectURI:  "https://your-app.com/callback",
    Scopes:       []string{"openid", "email", "profile"},
}

provider, err := upstream.NewOIDCProvider(ctx, config)
if err != nil {
    return err
}

// Build authorization URL
authURL, err := provider.AuthorizationURL(state, pkceChallenge, nonce)

// After callback, exchange code for tokens
tokens, err := provider.ExchangeCode(ctx, code, pkceVerifier)

Extensibility

To add a new IDP type (e.g., SAML), implement the Provider interface. The optional capability interfaces can be implemented as needed.

Index

Constants

This section is empty.

Variables

View Source
var ErrUserInfoSubjectMismatch = fmt.Errorf("userinfo subject does not match expected subject")

ErrUserInfoSubjectMismatch is returned when the UserInfo endpoint returns a subject that does not match the expected subject from the ID Token. This validation is required per OIDC Core Section 5.3.4 to prevent user impersonation.

Functions

func ValidateRedirectURI

func ValidateRedirectURI(uri string) error

ValidateRedirectURI validates an OAuth redirect URI according to RFC 6749 Section 3.1.2. It ensures the URI is:

  • A parseable, absolute URL with scheme and host
  • Free of fragments (per RFC 6749 Section 3.1.2.2)
  • Free of user credentials
  • Using http or https scheme only
  • Using HTTPS for non-loopback addresses (HTTP allowed only for 127.0.0.1, ::1, localhost)
  • Not containing wildcard hostnames

Types

type Config

type Config struct {
	// Issuer is the URL of the upstream IDP (e.g., https://accounts.google.com).
	Issuer string

	// ClientID is the OAuth client ID registered with the upstream IDP.
	ClientID string

	// ClientSecret is the OAuth client secret registered with the upstream IDP.
	ClientSecret string

	// Scopes are the OAuth scopes to request from the upstream IDP.
	Scopes []string

	// RedirectURI is the callback URL where the upstream IDP will redirect
	// after authentication. This should be our authorization server's callback endpoint.
	RedirectURI string
}

Config contains configuration for connecting to an upstream Identity Provider (e.g., Google, Okta, Auth0).

func (*Config) Validate

func (c *Config) Validate() error

Validate checks that the Config is valid.

type IDTokenClaims

type IDTokenClaims struct {
	// Issuer is the issuer identifier (iss claim).
	Issuer string

	// Subject is the subject identifier (sub claim).
	Subject string

	// Audience contains the audience(s) this ID Token is intended for (aud claim).
	Audience []string

	// ExpiresAt is the expiration time (exp claim).
	ExpiresAt time.Time

	// IssuedAt is the time at which the ID Token was issued (iat claim).
	IssuedAt time.Time

	// Nonce is the value used to associate a client session with an ID Token (nonce claim).
	Nonce string

	// AuthTime is the time when the end-user authentication occurred (auth_time claim).
	AuthTime time.Time

	// AuthorizedParty is the party to which the ID Token was issued (azp claim).
	AuthorizedParty string

	// Email is the user's email address.
	Email string

	// EmailVerified indicates whether the user's email has been verified.
	EmailVerified bool

	// Name is the user's full name.
	Name string

	// RawClaims contains all claims from the ID Token payload.
	RawClaims map[string]any
}

IDTokenClaims contains the standard OIDC ID Token claims. See OIDC Core Section 2 for claim definitions.

type IDTokenNonceValidator

type IDTokenNonceValidator interface {
	// ValidateIDTokenWithNonce validates an ID token with nonce verification.
	// Returns the parsed claims if validation succeeds, or an error if validation fails.
	ValidateIDTokenWithNonce(idToken, expectedNonce string) (*IDTokenClaims, error)
}

IDTokenNonceValidator is implemented by providers that support OIDC nonce validation. This is used to validate the nonce claim in ID tokens to prevent replay attacks.

type OIDCEndpoints

type OIDCEndpoints struct {
	// Issuer is the issuer identifier.
	Issuer string `json:"issuer"`

	// AuthorizationEndpoint is the URL for the authorization endpoint.
	AuthorizationEndpoint string `json:"authorization_endpoint"`

	// TokenEndpoint is the URL for the token endpoint.
	TokenEndpoint string `json:"token_endpoint"`

	// UserInfoEndpoint is the URL for the userinfo endpoint.
	UserInfoEndpoint string `json:"userinfo_endpoint,omitempty"`

	// JWKSEndpoint is the URL for the JWKS endpoint.
	JWKSEndpoint string `json:"jwks_uri,omitempty"`

	// CodeChallengeMethodsSupported lists the supported PKCE code challenge methods.
	CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"`
}

OIDCEndpoints contains the discovered endpoints for an OIDC provider.

type Provider

type Provider interface {
	// Name returns the provider name (e.g., "google", "oidc").
	Name() string

	// AuthorizationURL builds the URL to redirect the user to the upstream IDP.
	// state: our internal state to correlate callback
	// codeChallenge: PKCE challenge to send to upstream (if supported)
	// nonce: OIDC nonce for ID Token replay protection (per OIDC Core Section 3.1.2.1)
	AuthorizationURL(state, codeChallenge, nonce string) (string, error)

	// ExchangeCode exchanges an authorization code for tokens with the upstream IDP.
	ExchangeCode(ctx context.Context, code, codeVerifier string) (*Tokens, error)

	// RefreshTokens refreshes the upstream IDP tokens.
	RefreshTokens(ctx context.Context, refreshToken string) (*Tokens, error)

	// UserInfo fetches user information from the upstream IDP.
	UserInfo(ctx context.Context, accessToken string) (*UserInfo, error)
}

Provider handles communication with an upstream Identity Provider.

type Tokens

type Tokens struct {
	// AccessToken is the access token from the upstream IDP.
	AccessToken string

	// RefreshToken is the refresh token from the upstream IDP (if provided).
	RefreshToken string

	// IDToken is the ID token from the upstream IDP (for OIDC).
	IDToken string

	// ExpiresAt is when the access token expires.
	ExpiresAt time.Time
}

Tokens represents the tokens obtained from an upstream Identity Provider. This type is used for token exchange with the IDP, but stored separately (see storage.IDPTokens for the storage representation).

func (*Tokens) IsExpired

func (t *Tokens) IsExpired() bool

IsExpired returns true if the access token has expired or will expire within the buffer period. Returns true for nil receivers (treating nil tokens as expired).

type UserInfo

type UserInfo struct {
	// Subject is the unique identifier for the user (sub claim).
	Subject string `json:"sub"`

	// Email is the user's email address.
	Email string `json:"email,omitempty"`

	// Name is the user's full name.
	Name string `json:"name,omitempty"`

	// Claims contains all claims returned by the userinfo endpoint.
	Claims map[string]any `json:"-"`
}

UserInfo contains user information retrieved from the upstream IDP.

type UserInfoSubjectValidator

type UserInfoSubjectValidator interface {
	// UserInfoWithSubjectValidation fetches user info and validates the subject matches expected.
	// Returns ErrUserInfoSubjectMismatch if the subjects do not match.
	UserInfoWithSubjectValidation(ctx context.Context, accessToken, expectedSubject string) (*UserInfo, error)
}

UserInfoSubjectValidator is implemented by providers that support UserInfo subject validation per OIDC Core Section 5.3.4. This validation ensures the UserInfo response's subject matches the ID Token's subject to prevent user impersonation attacks.

Jump to

Keyboard shortcuts

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