upstreamtoken

package
v0.32.0 Latest Latest
Warning

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

Go to latest
Published: Jun 30, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package upstreamtoken provides a service for managing upstream IDP token lifecycle, including transparent refresh of expired access tokens.

Index

Constants

View Source
const TokenSessionIDClaimKey = "tsid"

TokenSessionIDClaimKey is the JWT claim key for the token session ID. This links JWT access tokens to stored upstream IDP tokens. We use "tsid" instead of "sid" to avoid confusion with OIDC session management which defines "sid" for different purposes (RFC 7519, OIDC Session Management).

Variables

View Source
var (
	// ErrSessionNotFound indicates no upstream tokens exist for the session.
	ErrSessionNotFound = errors.New("upstream tokens not found for session")

	// ErrNoRefreshToken indicates the access token is expired but no refresh
	// token is available to perform a refresh.
	ErrNoRefreshToken = errors.New("no refresh token available")

	// ErrRefreshFailed indicates a refresh failure (e.g., the
	// refresh token was revoked by the upstream IDP).
	ErrRefreshFailed = errors.New("upstream token refresh failed")

	// ErrInvalidBinding indicates token binding validation failed (e.g.,
	// subject or client ID mismatch between the stored token and the session).
	ErrInvalidBinding = errors.New("upstream token binding validation failed")
)

Sentinel errors returned by Service.GetValidTokens.

Functions

This section is empty.

Types

type InProcessService

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

InProcessService implements the Service interface for in-process use. It composes storage (read) and refresher (refresh + persist) to provide a single GetValidTokens call. Concurrent-refresh deduplication is delegated to the refresher's own singleflight.Group so the same Group covers both the handler's chain-walk path and the runtime token-swap path.

func NewInProcessService

func NewInProcessService(
	stor storage.UpstreamTokenStorage,
	refresher storage.UpstreamTokenRefresher,
) *InProcessService

NewInProcessService creates a new InProcessService. The refresher may be nil if upstream token refresh is not configured; expired tokens will return ErrNoRefreshToken in that case.

func (*InProcessService) GetAllUpstreamCredentials added in v0.32.0

func (s *InProcessService) GetAllUpstreamCredentials(
	ctx context.Context, sessionID string,
) (map[string]UpstreamCredential, []string, error)

GetAllUpstreamCredentials returns access tokens and ID tokens for all upstream providers in a session in a single storage round-trip. Expired access tokens are refreshed transparently; providers whose access token cannot be refreshed are included in the returned failed slice so downstream middleware can return a clean 401 for the access-token use case. The IDToken on a returned entry is the rotated ID token when a refresh produced one (OIDC Core 1.0 §12.2), otherwise the original JWT captured at the initial OIDC login; it is not independently validated for freshness and may be empty if the upstream login never yielded one. Callers MUST check its exp claim before use.

Returns an empty map and nil failed slice (not error) for unknown sessions.

func (*InProcessService) GetValidTokens

func (s *InProcessService) GetValidTokens(ctx context.Context, sessionID, providerName string) (*UpstreamCredential, error)

GetValidTokens returns a valid upstream credential for a session and provider. It transparently refreshes expired access tokens using the refresh token.

type Service

type Service interface {
	// GetValidTokens returns a valid upstream credential for a session and provider.
	// It transparently refreshes expired access tokens using the refresh token.
	// The providerName identifies which upstream provider's tokens to retrieve.
	//
	// Returns:
	//   - *UpstreamCredential on success
	//   - ErrSessionNotFound if no upstream tokens exist for the session/provider
	//   - ErrNoRefreshToken if the access token is expired and no refresh token is available
	//   - ErrRefreshFailed if the refresh attempt fails (e.g., revoked refresh token)
	//
	// The returned UpstreamCredential.IDToken may be empty or expired; callers
	// MUST check its `exp` claim before using it (e.g. as the subject_token of
	// an RFC 8693 token exchange). See UpstreamCredential for details.
	GetValidTokens(ctx context.Context, sessionID, providerName string) (*UpstreamCredential, error)
}

Service owns the upstream token lifecycle: read, refresh, error handling.

type TokenReader added in v0.13.0

type TokenReader interface {
	// GetAllUpstreamCredentials returns the access tokens (refreshing them if
	// expired) and ID tokens for every upstream provider associated with the
	// given session ID. Returns an empty map if the session has no stored
	// upstream tokens.
	//
	// The second return value contains the names of providers whose access tokens
	// were expired and could not be refreshed (e.g. the refresh token is missing
	// or the upstream IDP rejected the refresh). Those providers are omitted from
	// the creds map. Callers should treat a non-empty failed list as a signal to
	// return HTTP 401 + WWW-Authenticate so the client can re-authenticate.
	//
	// Each returned IDToken is the rotated ID token when a refresh produced
	// one (OIDC Core 1.0 §12.2), otherwise the original JWT captured at OIDC
	// login (OIDC Core 1.0 §3.1.3.7). Callers MUST check each ID token's `exp`
	// claim before using it for e.g. RFC 8693 subject-token exchange, as it may
	// be expired.
	//
	// Returns an empty map and nil failed slice (not error) for unknown sessions.
	GetAllUpstreamCredentials(ctx context.Context, sessionID string) (
		creds map[string]UpstreamCredential, failed []string, err error)
}

TokenReader retrieves upstream provider credentials for a session. This narrow interface decouples the auth middleware from storage internals.

type UpstreamCredential

type UpstreamCredential struct {
	AccessToken string
	IDToken     string
}

UpstreamCredential bundles the access token and the ID token for a single upstream provider. Access tokens are refreshed when expired.

The IDToken is the rotated ID token when a refresh produced one (OIDC Core 1.0 §12.2 permits but does not require a new id_token on refresh), otherwise the original JWT captured at the initial OIDC login (OIDC Core 1.0 §3.1.3.7). It is not independently validated for freshness.

Callers MUST check its `exp` claim before using it (e.g. as the subject_token of an RFC 8693 token exchange), as it may be expired. Note also that the ID token's `aud` is this auth server's client registration with the issuing upstream, not the token-exchange endpoint — whether a target authorization server accepts it as a subject token is governed by that server's policy and is typically limited to the same issuer/audience.

IDToken may be empty when the upstream login did not return an id_token (e.g. the provider was not asked for the openid scope). An empty IDToken is a legitimate state, not an error. Note that Identity.UpstreamTokens and Identity.UpstreamIDTokens are projected independently and are NOT guaranteed to share the same key set: a provider with an access token but no ID token appears only in UpstreamTokens.

Directories

Path Synopsis
Package mocks is a generated GoMock package.
Package mocks is a generated GoMock package.

Jump to

Keyboard shortcuts

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