issuer

package
v0.5.4 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 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

This section is empty.

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
}

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
}

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