verify

package
v1.9.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package verify verifies AuthKit tokens without a database: access tokens and RFC 9068 resource access tokens of the issuers a Verifier trusts, checked against their keys (a JWKS, static keys or a live key source). It also holds the claims, identity and context helpers and the net/http middleware, which authenticate through a *Verifier or an *authkit.Client (which adds API keys from its database).

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrSenderProofRequired refuses a bound token presented without its
	// proof: no TLS peer or another leaf, no or an invalid DPoP proof, or a
	// token verified detached from its request.
	ErrSenderProofRequired iam.Error = errmodel.E(errmodel.CodeSenderProofRequired)

	// ErrSenderProofUnavailable is a DPoP replay store failure: the request
	// is refused, not proven invalid.
	ErrSenderProofUnavailable = errors.New("sender proof replay protection unavailable")
	// ErrInvalidConfirmation refuses a cnf claim that is not exactly one
	// x5t#S256 or jkt thumbprint.
	ErrInvalidConfirmation iam.Error = errmodel.E(errmodel.CodeInvalidConfirmation)
	// ErrConfirmationWrongTokenType refuses cnf on a token type AuthKit does
	// not bind: an unenforced binding would be a silent downgrade.
	ErrConfirmationWrongTokenType iam.Error = errmodel.E(errmodel.CodeConfirmationWrongTokenType)
)

Sender-proof errors: RFC 8705 certificate-bound and RFC 9449 DPoP-bound resource tokens.

Functions

func AuthenticateRequest added in v0.147.0

func AuthenticateRequest(ctx context.Context, a Authenticator, r *http.Request) (auth.Verified, error)

AuthenticateRequest is r's helpers/auth Verified request, for code written against helpers/auth providers. Behind a gate over a (Required, Optional, RequireSession, RequirePermission or Sensitive, in any adapter) it reuses the gate's verification, since verifying again would spend a DPoP proof twice; otherwise it verifies r through a. When a is a PermissionChecker (*authkit.Client), its Can checks the credential's permissions live, the session included; otherwise it is identity only.

func AuthenticateSession added in v1.1.0

func AuthenticateSession(ctx context.Context, a Authority, r *http.Request) (auth.Verified, error)

AuthenticateSession is AuthenticateRequest plus RequireSession's session check, for identity-only code that must stop the moment a sign-in is revoked (billing, say): a user's token is auth.ErrRevoked once its sign-in is revoked. Unlike RequireSession, a credential that carries no sign-in (an API key) passes: verification already refuses it once revoked, and Can checks its authority live. Admitting only some kinds is the caller's policy (Verified.Identity()).

func DPoPChallenge added in v1.5.0

func DPoPChallenge(w http.ResponseWriter, r *http.Request, err error)

DPoPChallenge sets the RFC 9449 response headers for err, a failed authentication of r: WWW-Authenticate naming the DPoP error, and the DPoP-Nonce to retry with. It sets nothing for an error unrelated to DPoP. The gates call it; a host writing its own refusals calls it first.

func IdentityFromContext added in v0.147.0

func IdentityFromContext(ctx context.Context) (auth.Identity, bool)

IdentityFromContext is the identity of the claims the middleware stored in ctx (Claims.Identity). Behind a gate it carries AuthKit's credential state, so operations accept it; claims SetClaims stored, or ones with no AuthKit authority, describe the request and grant nothing. VerifiedIdentity also requires the gate to be over a given authenticator.

func Optional

func Optional(a Authenticator) func(http.Handler) http.Handler

Optional is Required when the request carries an Authorization header and passes it through anonymously otherwise. A present but invalid credential is refused.

func RequirePermission added in v0.65.0

func RequirePermission(a Authority, perm iam.Perm) func(http.Handler) http.Handler

RequirePermission authenticates the request (it includes Required) and requires perm, checked live, in the group attached to the request (WithGroup, or an adapter's SetGroup). The check includes the token's session: once it is revoked the request is 401 session_revoked. A request with no group fails closed: 500 internal_error, logged with its route. It panics at construction on a perm a does not register.

func RequirePermissionOn added in v0.147.0

func RequirePermissionOn(a Authority, ref iam.GroupRef, perm iam.Perm) func(http.Handler) http.Handler

RequirePermissionOn is RequirePermission in one fixed group, such as iam.RootGroup().

func RequireSession added in v0.147.0

func RequireSession(a Authority) func(http.Handler) http.Handler

RequireSession is Required plus the session check: the session or device key the token was minted from is still active (not logged out, revoked, banned or deleted), or the request is 401 session_revoked. A user's token passes while its sign-in stands; any other credential is 403 forbidden.

func Required

func Required(a Authenticator) func(http.Handler) http.Handler

Required authenticates every request through a, storing its claims and identity in the request context, and answers 401 otherwise. It is stateless: a token outlives its revoked session until it expires. The live gates (RequireSession, RequirePermission, Sensitive) include it.

Stacked gates over the same a verify a request once: the first stores the claims and the later ones, and AuthenticateRequest and AuthenticateSession behind them, reuse them, so a DPoP proof is spent and an API key looked up once. Claims another authenticator verified, or verified for another credential, or stored by SetClaims are verified again.

func Sensitive added in v0.54.0

func Sensitive(a Authority) func(http.Handler) http.Handler

Sensitive is RequireSession plus a recent sign-in of the user's own token: within the last 15 minutes, with the second factor when the account has one. A stale sign-in answers 403 step_up_required with the account's step-up methods, which auth-ui handles; any other credential is 403 forbidden. Stack it after RequirePermission when a route needs both.

func SetClaims

func SetClaims(ctx context.Context, cl Claims) context.Context

SetClaims stores cl in ctx for the handlers. Nothing trusts claims stored this way: the gates and AuthenticateRequest verify the request themselves, and their identity (IdentityFromContext) grants nothing.

func VerifiedIdentity added in v1.7.0

func VerifiedIdentity(ctx context.Context, a Authenticator) (auth.Identity, bool)

VerifiedIdentity is the identity a gate over a verified and stored in ctx (IdentityFromContext), as helpers/auth Auth.Identity reports it. It is false without one, and for claims SetClaims or a gate over another authenticator stored: only a gate's own verification proves who called.

func WithGroup added in v0.147.0

func WithGroup(ctx context.Context, ref iam.GroupRef) context.Context

WithGroup attaches the permission group a request acts in, for RequirePermission: the route's loader sets it once it has resolved the URL to its entity (a channel's group).

Types

type Authenticator added in v0.147.0

type Authenticator interface {
	VerifyRequest(r *http.Request) (Claims, error)
}

Authenticator authenticates requests: a *Verifier, or an *authkit.Client, which also accepts its API keys and its remote applications' tokens.

type Authority added in v0.147.0

type Authority interface {
	Authenticator
	PermissionChecker
	SessionChecker
}

Authority authenticates requests and checks sessions and permissions live: what the live gates need. *authkit.Client is one.

type Claims

type Claims struct {
	Kind TokenKind
	// JOSEType is the token's typ header ("access+jwt", "at+jwt"); empty
	// for an API key.
	JOSEType string
	// Issuer is the validated iss.
	Issuer string

	// UserID is a local user: set only for an issuer registered IsLocal.
	UserID string
	// Subject is another issuer's user, or a resource access token's sub
	// (its user, or its client acting for itself) whichever issuer minted it.
	// It is meaningful only with Issuer and never names a local user.
	Subject string
	// SessionID (sid) or DeviceKeyID names the sign-in a native token was
	// minted from; the session check refuses the token once it is revoked.
	SessionID   string
	DeviceKeyID string
	// APIKeyID is the key an API-key credential resolved to.
	APIKeyID string
	// Group binds an API key's authority to the group it was granted in;
	// nil otherwise.
	Group *PermissionScope

	// Permissions are the credential's permission strings: an API key's
	// stored grants, or a resource access token's grant for its audience (the
	// user's permissions within the resource server's ceiling at mint).
	// Native user tokens carry none; their authority is read live (Can).
	Permissions []string
	// Entitlements is the issuer's token-time entitlements snapshot.
	Entitlements []string
	// RootRole is the user's root-group role at mint ("root:admin"), for
	// display only: UI and content visibility without a database call. It is
	// stale up to the token lifetime and never authorizes anything; every
	// permission check reads the role live.
	RootRole string

	Email         string
	EmailVerified bool
	Username      string

	// AMR, ACR and AuthTime describe the sign-in the token carries.
	AMR      []string
	ACR      string
	AuthTime time.Time
	// TwoFAEnrollment marks a token that reaches only AuthKit's 2FA
	// enrollment routes; every verifier refuses it elsewhere.
	TwoFAEnrollment bool
	// MFAEnrolled is whether the user had a usable second factor at mint.
	MFAEnrolled bool
	JTI         string

	// ClientID is the OAuth client a resource access token was issued to;
	// Scopes its granted scopes and Roles the user's role names at mint, for
	// display only.
	ClientID string
	Scopes   []string
	Roles    []string
	// AuthorizationDetails is a resource access token's RFC 9396 grant, the
	// raw JSON array; nil when it carries none.
	AuthorizationDetails json.RawMessage
	// Invoker is the client acting for the user, from token exchange: the
	// RFC 8693 identity claim (act.sub), the Identity's Invoker.
	Invoker string
	// CustomClaims are a resource access token's claims named by an absolute
	// URI ("https://example.com/grant"), the issuer's own, each value raw JSON.
	CustomClaims map[string]json.RawMessage

	// CertificateThumbprint (cnf x5t#S256) or JWKThumbprint (cnf jkt) is a
	// resource token's sender binding, already matched against
	// this request's TLS peer certificate or DPoP proof; empty for a bearer
	// token.
	CertificateThumbprint string
	JWKThumbprint         string
}

Claims is a verified credential: what the middleware stores in the request context. Kind says which fields apply.

func ClaimsFromContext

func ClaimsFromContext(ctx context.Context) (Claims, bool)

ClaimsFromContext is the claims the middleware stored in ctx.

func (Claims) HasAMR added in v0.52.0

func (c Claims) HasAMR(m string) bool

HasAMR reports whether the sign-in used authentication method m.

func (Claims) HasEntitlement

func (c Claims) HasEntitlement(ent string) bool

HasEntitlement reports whether the claims carry entitlement ent.

func (Claims) HasPermission

func (c Claims) HasPermission(perm iam.Perm) bool

HasPermission reports whether the claims carry a permission covering perm.

func (Claims) HasScope added in v1.5.0

func (c Claims) HasScope(scope string) bool

HasScope reports whether a resource access token was granted scope.

func (Claims) Identity added in v0.147.0

func (c Claims) Identity() (auth.Identity, bool)

Identity is the claims' provider-neutral identity (helpers/auth): the Subject, native to Issuer, whose authority the credential uses; the Invoker who actually acts, the subject itself unless someone acts on its behalf; and the Credential that proved it, never the subject.

  • A user's token is the user, by its session or device key.
  • An OAuth client's client-credentials token is the client; its token for a user is the user, invoked by the client.
  • An API key is a credential of its group's account, an application whose id is the group's, so rotating keys never changes the subject.

ok is false when they name no subject under an issuer.

func (Claims) IsResourceToken added in v1.5.0

func (c Claims) IsResourceToken() bool

IsResourceToken reports whether the claims are an RFC 9068 resource access token's (at+jwt): an authorization server's grant to a client for this resource server, never a sign-in of this deployment.

func (Claims) IsUser added in v0.72.0

func (c Claims) IsUser() bool

IsUser reports whether the claims are a local user's.

type IssuerKeyStatus added in v0.143.0

type IssuerKeyStatus = jwks.Status

IssuerKeyStatus is one JWKS issuer's key-refresh state: key count, freshness, the age of the last successful fetch against MaxStale, and the last error.

type IssuerOptions

type IssuerOptions struct {
	// JWKSURI is fetched on first use and refreshed in the background when
	// its keys expire or an unknown kid arrives. Expired keys keep verifying
	// while refreshes fail, up to MaxStale.
	JWKSURI string
	// Keys are static public keys (PEM or JWK), each with its kid. Replace
	// them by calling AddIssuer again.
	Keys []iam.RemoteApplicationKey
	// KeySource is read live on every verification: a co-located, rotating
	// key source such as AuthKit's own.
	KeySource keys.Source

	// CacheTTL is how long fetched JWKS keys are fresh (default 10m).
	CacheTTL time.Duration
	// MaxStale bounds how long after the last successful fetch JWKS keys
	// keep verifying while refreshes fail, so a peer's key revocation cannot
	// be suppressed by blocking the fetch. Past it the issuer's tokens fail
	// with 503 issuer_keys_unavailable. Default 4h; never below CacheTTL.
	MaxStale time.Duration

	// IsLocal marks the issuer whose users are this host's own: only its
	// access tokens set Claims.UserID (others set Subject).
	IsLocal bool
}

IssuerOptions is where an issuer's keys come from: exactly one of JWKSURI, Keys and KeySource.

type PermissionChecker added in v0.65.0

type PermissionChecker interface {
	Can(ctx context.Context, identity auth.Identity, ref iam.GroupRef, perm iam.Perm) (bool, error)
	// KnownPermission reports whether perm is registered.
	KnownPermission(perm iam.Perm) bool
}

PermissionChecker checks an identity's authority in a group live; *authkit.Client is one. Can is false for an unknown group, an identity bound to another group or one without AuthKit's credential state, iam.ErrSessionRevoked once the identity's session is revoked, and iam.ErrUnknownPermission for an unregistered perm.

type PermissionScope added in v0.65.0

type PermissionScope struct {
	GroupID         string
	AuthorityIssuer string
	Persona         iam.Persona
}

PermissionScope is a credential's group binding: the group, the issuer whose group it is, and the group's persona.

type SessionChecker added in v0.147.0

type SessionChecker interface {
	// CheckSession: the session or device key the token was minted from is
	// still active. A user's token carries one.
	CheckSession(ctx context.Context, cl Claims) error
	// CheckRecentSignIn: CheckSession, and the user's own token, signed in
	// recently enough for a sensitive action, with the second factor when
	// the account has one.
	CheckRecentSignIn(ctx context.Context, cl Claims) error
}

SessionChecker checks the sign-in behind verified claims live; *authkit.Client is one. Both return nil or the error to answer: iam.ErrSessionRevoked, forbidden for a credential that carries no sign-in, or (CheckRecentSignIn) step_up_required carrying the step-up methods.

type TokenKind added in v1.7.0

type TokenKind string

TokenKind is the class of credential verified Claims hold: which of their fields apply. It is not the subject's kind (Claims.Identity).

const (
	// TokenUser is a user's token: a native one (UserID), another issuer's
	// (Subject), or a resource access token for a user.
	TokenUser TokenKind = "user"
	// TokenAPIKey is one of this deployment's API keys (*authkit.Client).
	TokenAPIKey TokenKind = "api_key"
	// TokenOAuthClient is an OAuth client's own resource access token
	// (at+jwt) whose sub is its client_id. It carries no AuthKit authority.
	TokenOAuthClient TokenKind = "oauth_client"
)

type Verifier

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

Verifier verifies tokens from the issuers added with AddIssuer.

func NewVerifier

func NewVerifier(opts ...VerifierOption) *Verifier

NewVerifier returns a Verifier that trusts no issuer until AddIssuer. It panics on a WithDPoPNonce key shorter than 32 bytes.

func (*Verifier) AddIssuer

func (v *Verifier) AddIssuer(issuerID string, audiences []string, opts IssuerOptions) error

AddIssuer trusts issuerID's tokens for any of audiences, replacing an earlier registration of it. A failure leaves the earlier one in place.

func (*Verifier) AuthenticateRequest added in v0.126.0

func (v *Verifier) AuthenticateRequest(ctx context.Context, r *http.Request) (auth.Verified, error)

AuthenticateRequest is r's helpers/auth Verified request, identity only: a Verifier checks no permissions.

func (*Verifier) CheckIssuerKeys added in v0.143.0

func (v *Verifier) CheckIssuerKeys(context.Context) error

CheckIssuerKeys is a no-I/O health probe: it fails naming every JWKS issuer whose last key fetch failed, with the age of its keys and whether they are past MaxStale (its tokens then fail closed). Other issuers are unaffected.

func (*Verifier) IssuerKeyStatuses added in v0.143.0

func (v *Verifier) IssuerKeyStatuses() []IssuerKeyStatus

IssuerKeyStatuses reports every JWKS issuer's key state, sorted by issuer.

func (*Verifier) RemoveIssuer

func (v *Verifier) RemoveIssuer(issuerID string)

RemoveIssuer stops trusting issuerID's tokens and drops its cached keys.

func (*Verifier) Verify

func (v *Verifier) Verify(ctx context.Context, token string) (Claims, error)

Verify verifies a token detached from any request, so a sender-bound token fails with ErrSenderProofRequired (use VerifyRequest). ctx bounds the key fetches.

func (*Verifier) VerifyClaims

func (v *Verifier) VerifyClaims(ctx context.Context, token string) (map[string]any, error)

VerifyClaims verifies a token's signature, issuer, audience and times and returns its raw claims, for host-defined token profiles: it enforces no AuthKit token type, subject, permission or sender binding. Use Verify or VerifyRequest for AuthKit tokens.

func (*Verifier) VerifyRequest added in v0.65.0

func (v *Verifier) VerifyRequest(r *http.Request) (Claims, error)

VerifyRequest verifies the request's bearer (or DPoP) token, its sender proof included. It is stateless: a token outlives its revoked session until it expires; RequireSession, RequirePermission and Sensitive check the session live (through *authkit.Client).

type VerifierOption

type VerifierOption func(*verifierConfig)

VerifierOption configures a Verifier.

func WithDPoP added in v0.101.0

func WithDPoP(replay func(ctx context.Context, key string, ttl time.Duration) (bool, error)) VerifierOption

WithDPoP accepts RFC 9449 DPoP-bound tokens, with WithPublicURL. replay is the proof replay store: it atomically claims key until ttl and returns true only for the first claim; every replica must share it, and its errors fail closed. Client.NewVerifier wires AuthKit's own.

func WithDPoPNonce added in v1.5.0

func WithDPoPNonce(key []byte) VerifierOption

WithDPoPNonce requires every DPoP proof to carry a server nonce (RFC 9449 §8). A proof without a current one is refused 401 use_dpop_nonce with a fresh nonce in the DPoP-Nonce header (DPoPChallenge), which the client retries with. key, at least 32 random bytes, keys the nonces; every replica must share it.

func WithHTTPClient

func WithHTTPClient(client *http.Client) VerifierOption

WithHTTPClient sets the client JWKS are fetched with (default: a timeout-bounded client).

func WithPublicURL added in v0.149.0

func WithPublicURL(url string) VerifierOption

WithPublicURL is where clients reach the paths this verifier sees: "https://api.example.com", or "https://example.com/api" when a proxy in front strips /api. A DPoP proof must name it plus the request's path, the rule HTTPConfig.PublicURL sets for AuthKit's own routes. No Host or Forwarded header is consulted.

func WithSkew

func WithSkew(d time.Duration) VerifierOption

WithSkew sets the clock skew allowed on exp, nbf and iat (default 60s).

Jump to

Keyboard shortcuts

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