oidc

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package oidc provides a thin adapter over coreos/go-oidc v3 and golang.org/x/oauth2 for OpenID Connect authentication.

This package intentionally does NOT re-define SDK types. It exposes go-oidc's Provider, IDToken, and oauth2's Token directly. The adapter adds GoCell-specific concerns: Config, errcode wrapping, and HTTP client lifecycle.

ref: github.com/coreos/go-oidc/v3/oidc ref: golang.org/x/oauth2

Index

Constants

View Source
const (
	ErrAdapterOIDCConfig    errcode.Code = "ERR_ADAPTER_OIDC_CONFIG"
	ErrAdapterOIDCDiscovery errcode.Code = "ERR_ADAPTER_OIDC_DISCOVERY"
	ErrAdapterOIDCVerify    errcode.Code = "ERR_ADAPTER_OIDC_VERIFY"

	ErrAdapterOIDCExchange errcode.Code = "ERR_ADAPTER_OIDC_TOKEN"
	ErrAdapterOIDCUserInfo errcode.Code = "ERR_ADAPTER_OIDC_USERINFO"
)

OIDC adapter error codes.

ErrAdapterOIDCExchange is named "Exchange" but its wire literal stays "ERR_ADAPTER_OIDC_TOKEN" — the constant was renamed to dodge a gosec G101 false positive on "Token" while keeping the existing wire value stable for downstream consumers (logs, error fingerprints, dashboards).

View Source
const ProbeReady healthz.ProbeName = "oidc_ready"

ProbeReady is the ops-contract name for the OIDC readiness probe. healthz.ProbeName-typed, funneled by PROBENAME-SEALED-FUNNEL-01.

Variables

This section is empty.

Functions

This section is empty.

Types

type Adapter

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

Adapter is a thin wrapper over go-oidc and oauth2. It manages provider discovery and exposes the underlying go-oidc types directly.

func New

func New(ctx context.Context, clk clock.Clock, cfg Config) (*Adapter, error)

New creates an OIDC Adapter and synchronously performs OIDC discovery. An unreachable or misconfigured issuer causes construction to fail immediately (fail-fast at boot, not at first request).

clk is required: New panics via clock.MustHaveClock when clk is nil. Use clock.Real() at the composition root; inject clockmock.New() in tests.

ref: coreos/go-oidc — Provider.NewProvider semantics (sync HTTP round-trip). ref: adapters/s3.New — same clock.MustHaveClock + state-machine field pattern.

func (*Adapter) Close

func (a *Adapter) Close(ctx context.Context) error

Close implements lifecycle.ManagedResource. It signals the worker to stop and waits for the goroutine to drain, bounded by ctx. Idempotent — safe to call from both Worker.Stop and ManagedResource.Close teardown paths.

Fast path: if the worker goroutine was never started (e.g. bootstrap aborted before Worker.Start was called), workerDone will never be closed. In that case we skip the select so we do not burn the shutdown budget on a non-existent drain.

ref: adapters/s3.Client.Close — same idempotent + ctx-bounded pattern.

func (*Adapter) OAuth2Config

func (a *Adapter) OAuth2Config(ctx context.Context) (*oauth2.Config, error)

OAuth2Config returns an oauth2.Config using the provider's endpoints.

func (*Adapter) Probes

func (a *Adapter) Probes() []healthz.Probe

Probes returns the typed readyz probe for the OIDC provider. The probe verifies that the cached provider is populated without re-discovering.

ref: kubernetes/kubernetes pkg/util/healthz — named health checkers.

func (*Adapter) Provider

func (a *Adapter) Provider(_ context.Context) (*gooidc.Provider, error)

Provider returns the cached go-oidc Provider. Discovery runs synchronously in New (fail-fast at boot), so a successfully constructed Adapter always has a populated provider. This read is lock-free (atomic.Pointer.Load); the refresh worker swaps the pointer atomically and never blocks readers, even across a slow or hung re-discovery (post-init fail-open availability).

IMPORTANT: The cached provider never expires automatically. The refresh worker (Worker(), auto-wired by bootstrap.WithManagedResource) re-discovers every refreshInterval to pick up OIDC metadata rotation.

func (*Adapter) Refresh

func (a *Adapter) Refresh(ctx context.Context) (*gooidc.Provider, error)

Refresh re-discovers the OIDC provider metadata and atomically swaps the cached provider. The refresh worker calls this on each tick; it is also safe to call manually.

func (*Adapter) Verifier

func (a *Adapter) Verifier(ctx context.Context) (*gooidc.IDTokenVerifier, error)

Verifier returns a go-oidc IDTokenVerifier for the configured client ID.

func (*Adapter) Worker

func (a *Adapter) Worker() worker.Worker

Worker returns a worker.Worker that drives the periodic OIDC re-discovery loop. Bootstrap wires this via WorkerGroup so the loop starts with the service lifecycle.

ref: adapters/s3.Client.Worker — same worker-adapter pattern.

type Config

type Config struct {
	IssuerURL    string
	ClientID     string
	ClientSecret string
	RedirectURL  string
	Scopes       []string      // default: [openid, profile, email]
	HTTPTimeout  time.Duration // default: 10s

	// RefreshInterval controls how often the worker re-discovers OIDC provider
	// metadata. Zero means defaultOIDCRefreshInterval (24h).
	RefreshInterval time.Duration

	// RefreshCollector receives success/failure signals from the refresh worker.
	// Optional: nil is replaced with NoopRefreshCollector{} in New().
	RefreshCollector RefreshCollector
}

Config holds the OIDC provider configuration.

func (Config) Validate

func (c Config) Validate() error

Validate checks required fields.

type NoopRefreshCollector

type NoopRefreshCollector struct{}

NoopRefreshCollector is the default collector used when no observability is wired. Method body intentionally empty — registration cost is zero and metric absence is documented behavior, not a fault.

func (NoopRefreshCollector) RecordRefresh

func (NoopRefreshCollector) RecordRefresh(_ context.Context, _ bool)

RecordRefresh is a no-op.

type RefreshCollector

type RefreshCollector interface {
	// RecordRefresh increments the refresh counter.
	// success=true means discovery succeeded and a.provider was updated;
	// success=false means discovery failed (fail-open: old provider kept).
	RecordRefresh(ctx context.Context, success bool)
}

RefreshCollector observes OIDC JWKS refresh attempts so alerting rules can detect stale discovery metadata without parsing log strings.

Implementations must be safe for concurrent use.

ref: adapters/rabbitmq.PublisherCollector — same inject-at-construction pattern.

func NewProviderRefreshCollector

func NewProviderRefreshCollector(p metrics.Provider, cellID string) (RefreshCollector, error)

NewProviderRefreshCollector registers the oidc_jwks_refresh_total counter on p and returns a RefreshCollector backed by it. Returns error when cellID is empty or when the Provider reports registration failure (typically duplicate metric names).

Jump to

Keyboard shortcuts

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