Help us shape the future of Go! Take the 2026 Go Developer Survey

issuer

package
v0.5.8 Latest Latest
Warning

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

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

Documentation

Overview

Package issuer verifies tokens from a trusted external issuer, so a platform that already authenticates its users can open a Dexaflow UI session for them without holding Dexaflow's own signing secret (#1284).

The issuer signs with its own key and publishes it as a JWKS; Dexaflow only ever reads public keys. A verified token names an existing user (by the issuer's subject) in an allowed tenant. It never creates users and never grants roles: roles stay whatever the user row holds.

Index

Constants

View Source
const DefaultBearerMaxLifetime = 15 * time.Minute

DefaultBearerMaxLifetime bounds exp - iat of a bearer when Config.BearerMaxLifetime is zero. A bearer is reused until it expires and cannot be revoked before then, so it is kept short; the user it names is still reloaded on every request.

View Source
const DefaultMaxLifetime = 2 * time.Minute

DefaultMaxLifetime bounds exp - iat when Config.MaxLifetime is zero. A handoff is posted the moment it is minted, so two minutes is generous.

View Source
const KeyRefreshCooldown = 30 * time.Second

KeyRefreshCooldown is the least time between two downloads of the issuer's JWKS. A token whose key is not cached triggers a download, and anyone can mint such a token, so without a floor every forged request would cost an outbound call to the issuer. A real key rotation is picked up at most this long after the previous download.

Variables

View Source
var (
	// ErrInvalidToken covers a bad signature, issuer, audience, expiry or a
	// missing subject or jti: the token is not one the trusted issuer made for
	// us.
	ErrInvalidToken = errors.New("issuer: invalid token")
	// ErrLifetime is a token without iat, one valid for longer than
	// MaxLifetime, or one issued in the future. A handoff token is meant to be
	// used once, right away; a long or post-dated one is a long replay window.
	ErrLifetime = errors.New("issuer: token lifetime missing or too long")
	// ErrTenantNotAllowed is a tenant claim that is absent, not a string, or
	// not in AllowedTenants.
	ErrTenantNotAllowed = errors.New("issuer: tenant not allowed")
	// ErrReplayed is a token whose jti this server already accepted. A handoff
	// token opens one session; a second post of the same token is a replay.
	ErrReplayed = errors.New("issuer: token already used")
)

Verification failures. Each is fail-closed; callers log the class and show the browser nothing more specific than "not signed in".

View Source
var ErrBearerDisabled = errors.New("issuer: bearer tokens are not enabled")

ErrBearerDisabled is a bearer presented while Config.BearerAudiences is empty: the operator has not turned the bearer mode on.

View Source
var ErrKeysUnavailable = errors.New("issuer: signing keys unavailable")

ErrKeysUnavailable is a token that could not be checked because the issuer's JWKS could not be downloaded. It says nothing about the token, so the API answers 503 rather than "sign in again".

Functions

func MarkKeyOutage added in v0.5.5

func MarkKeyOutage(ctx context.Context)

MarkKeyOutage records on a context from TrackKeyOutage that the keys could not be obtained, for a key set that finds its keys some other way first (an OpenID discovery document, say).

func NewKeySet added in v0.5.5

func NewKeySet(url string, algs []string, now func() time.Time) gooidc.KeySet

NewKeySet returns the JWKS published at url as a go-oidc key set, with the cache, the refresh cooldown and the size and time bounds the trusted issuer uses. It makes no network call until a signature is checked. Only algs are accepted. The CI OIDC issuers (ADR 0092) share it.

func TrackKeyOutage added in v0.5.5

func TrackKeyOutage(ctx context.Context) (tracked context.Context, outage func() bool)

TrackKeyOutage returns a context to verify a token with, and a function that reports, after the verification, whether it failed because the keys could not be downloaded rather than because the token is bad.

Types

type Config

type Config struct {
	// Name identifies the issuer inside Dexaflow. Its users are linked by
	// (Provider(), subject), so it must stay stable once users exist.
	Name string
	// Issuer is the exact `iss` the tokens carry.
	Issuer string
	// JWKSURL is where the issuer publishes its public signing keys.
	JWKSURL string
	// Audience is the `aud` the tokens must carry for this Dexaflow.
	Audience string
	// TenantClaim names the string claim carrying the Dexaflow tenant name.
	TenantClaim string
	// AllowedTenants lists the tenants this issuer may sign in to; "*" allows
	// every tenant.
	AllowedTenants []string
	// MaxLifetime caps exp - iat; zero means DefaultMaxLifetime.
	MaxLifetime time.Duration
	// BearerAudiences are the `aud` values of tokens accepted as a bearer on
	// every request (VerifyBearer). Empty turns the bearer mode off. They must
	// differ from Audience, so a handoff token is never a bearer.
	BearerAudiences []string
	// BearerMaxLifetime caps exp - iat of a bearer; zero means
	// DefaultBearerMaxLifetime.
	BearerMaxLifetime time.Duration
	// DeployAudience is the `aud` of the bearers that may deploy when the
	// operator makes the issuer the only way to deploy (#1773). It is a
	// bearer audience of its own, accepted even when BearerAudiences is
	// empty, and VerifyBearer marks a token whose aud is it alone
	// (Identity.DeployAudience).
	// Empty means no deploy audience.
	DeployAudience string
}

Config is one trusted issuer.

type Identity

type Identity struct {
	Subject string
	Email   string
	Tenant  string
	// Scopes are a bearer token's OAuth scopes (ADR 0067); nil for a handoff
	// token, whose session is not scoped.
	Scopes []string
	// DeployAudience is true for a bearer whose `aud` is Config.DeployAudience
	// alone (#1773); a token that also names another audience is not one. It says where the token was minted for,
	// not what it may do: its scopes still decide that.
	DeployAudience bool
}

Identity is what a verified token says about the user.

type Verifier

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

Verifier checks tokens against one trusted issuer.

func New

func New(_ context.Context, cfg Config) *Verifier

New builds a Verifier. It makes no network call: the JWKS is fetched on the first Verify and cached, refreshed when a token names an unknown key id (at most once per KeyRefreshCooldown), so key rotation needs no restart and an issuer outage cannot block boot. The handoff and the bearer share the cache.

func (*Verifier) BearerEnabled added in v0.5.3

func (v *Verifier) BearerEnabled() bool

BearerEnabled reports whether any bearer audience, the deploy audience included, is configured.

func (*Verifier) Provider

func (v *Verifier) Provider() string

Provider is the key this issuer's users are linked under (the users table's oidc_provider). The "issuer:" prefix keeps it apart from OIDC provider names.

func (*Verifier) Verify

func (v *Verifier) Verify(ctx context.Context, raw string) (*Identity, error)

Verify checks raw and returns the identity it carries.

func (*Verifier) VerifyBearer added in v0.5.3

func (v *Verifier) VerifyBearer(ctx context.Context, raw string) (*Identity, error)

VerifyBearer checks a token sent as a bearer on an API request, the way a remote MCP client sends one on every call (ADR 0050 D9). It applies the handoff's checks (signature, issuer, expiry, subject, bounded lifetime, allowed tenant) with two differences: the audience must be one of BearerAudiences or the DeployAudience and never the handoff Audience, and there is no one-use rule, because the same token authenticates every request until it expires.

Jump to

Keyboard shortcuts

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