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 ¶
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.
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.
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 ¶
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".
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.
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 ¶
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
BearerEnabled reports whether any bearer audience is configured.
func (*Verifier) Provider ¶
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) VerifyBearer ¶ added in v0.5.3
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.