Documentation
¶
Index ¶
- Constants
- Variables
- func Allow(ctx context.Context, checker PermissionChecker, cl Claims, perm authkit.Perm, ...) (bool, error)
- func NewSSRFGuardedClient() *http.Client
- func Optional(v *Verifier) func(http.Handler) http.Handler
- func RequirePermission(checker PermissionChecker, perm authkit.Perm, ...) func(http.Handler) http.Handler
- func Required(v *Verifier) func(http.Handler) http.Handler
- func RequiredLive(v *Verifier) (func(http.Handler) http.Handler, error)
- func Sensitive(options ...SensitiveOptions) func(http.Handler) http.Handler
- func SensitiveClaims(cl Claims, options ...SensitiveOptions) bool
- func SetClaims(ctx context.Context, cl Claims) context.Context
- func WithPermissionScope(ctx context.Context, scope PermissionScope) context.Context
- type Claims
- func (c Claims) Attribute(key string) (json.RawMessage, bool)
- func (c Claims) AuthenticatedWithin(maxAge time.Duration) bool
- func (c Claims) BoundToPermissionGroup() bool
- func (c Claims) Delegated() (DelegatedPrincipal, bool)
- func (c Claims) DelegatedAccess() (DelegatedPrincipal, bool)
- func (c Claims) DocumentReference(documentType string) (documents.Reference, bool)
- func (c Claims) HasAMR(method string) bool
- func (c Claims) HasEntitlement(ent string) bool
- func (c Claims) HasPermission(perm authkit.Perm) bool
- func (c Claims) HasRole(role string) bool
- func (c Claims) IsDelegatedAccessToken() bool
- func (c Claims) IsUser() bool
- func (c Claims) PermissionGroupAllows(scope PermissionScope) bool
- func (c Claims) Principal() authkit.Principal
- func (c Claims) PrincipalKind() authkit.PrincipalKind
- type DelegatedPrincipal
- type Enricher
- type FederationStats
- type IssuerKey
- type IssuerOptions
- type LivenessSource
- type PermissionChecker
- type PermissionScope
- type PermissionValidator
- type RemoteApplicationSource
- type SensitiveOptions
- type ServiceJWTVerifyOption
- type Verifier
- func (v *Verifier) AddIssuer(issuerID string, audiences []string, opts IssuerOptions) error
- func (v *Verifier) AddMFAEnrollmentExemptRoutes(paths []string) *Verifier
- func (v *Verifier) AllowLive(ctx context.Context, checker PermissionChecker, cl Claims, perm authkit.Perm, ...) (bool, error)
- func (v *Verifier) FederationStats() FederationStats
- func (v *Verifier) HTTPClient() *http.Client
- func (v *Verifier) HasLiveness() bool
- func (v *Verifier) IsLive(ctx context.Context, cl Claims) (bool, authkit.UserLiveness, error)
- func (v *Verifier) LoadRemoteApplications(ctx context.Context, src RemoteApplicationSource, audiences []string) error
- func (v *Verifier) RemoveIssuer(issuerID string)
- func (v *Verifier) SetMFAEnrollmentExemptPaths(paths []string) *Verifier
- func (v *Verifier) SetRemoteApplicationSource(src RemoteApplicationSource)
- func (v *Verifier) ValidateDocumentIssuer(ctx context.Context, issuer string) error
- func (v *Verifier) Verify(ctx context.Context, tokenStr string) (Claims, error)
- func (v *Verifier) VerifyClaims(ctx context.Context, tokenStr string) (jwt.MapClaims, error)
- func (v *Verifier) VerifyDelegatedAccess(ctx context.Context, tokenStr string) (Claims, DelegatedPrincipal, error)
- func (v *Verifier) VerifyDelegatedAccessRequest(r *http.Request) (Claims, DelegatedPrincipal, error)
- func (v *Verifier) VerifyDocument(ctx context.Context, document documents.SignedDocument, ...) (documents.Envelope, error)
- func (v *Verifier) VerifyRequest(r *http.Request) (Claims, error)
- func (v *Verifier) VerifyRequestLive(r *http.Request) (Claims, error)
- func (v *Verifier) VerifyServiceJWT(ctx context.Context, tokenStr string, opts ...ServiceJWTVerifyOption) (authkit.ServiceJWTClaims, error)
- func (v *Verifier) WithLiveness(src LivenessSource) *Verifier
- func (v *Verifier) WithService(svc Enricher) *Verifier
- type VerifierOption
- func WithAPIKeyPrefix(prefix string) VerifierOption
- func WithAlgorithms(algs ...string) VerifierOption
- func WithHTTPClient(c *http.Client) VerifierOption
- func WithPermissions(fn PermissionValidator) VerifierOption
- func WithRemoteApplicationAudiences(audiences ...string) VerifierOption
- func WithRequireMFAEnrollment(require bool) VerifierOption
- func WithSSRFGuard() VerifierOption
- func WithSkew(d time.Duration) VerifierOption
Constants ¶
const ( AccessTokenType = jwtkit.AccessTokenType DelegatedAccessTokenType = jwtkit.DelegatedAccessTokenType RemoteApplicationAccessTokenType = jwtkit.RemoteApplicationAccessTokenType )
Token-type tags used by the verification layer. Sourced from jwtkit so they stay in lockstep with the signer; authhttp exposes the same values via its own delegation.go constants.
const APIKeyPrincipalType = "api-key"
APIKeyPrincipalType is the TokenType value carried by an opaque API key: a machine credential, not a user.
const DefaultOutboundTimeout = netguard.DefaultTimeout
DefaultOutboundTimeout bounds the verify layer's outbound HTTP calls (JWKS fetches).
const DefaultSensitiveMaxAge = 15 * time.Minute
const MaxDelegatedRoles = 64
MaxDelegatedRoles bounds how many role UUIDs we lift from attributes.roles on a delegated token, so a hostile issuer can't inflate a principal unboundedly.
const RemoteApplicationTokenType = "remote_application"
RemoteApplicationTokenType is the TokenType value carried by a remote application access token: a remote_application acting AS ITSELF. Like an API-key principal it carries Permissions (its STORED authority) but no UserID; the live-user enrichment/ban gate is skipped (there is no user).
Variables ¶
var ( // ErrSenderProofRequired rejects a certificate-bound token presented // without its certificate: no TLS peer, a different leaf, or a token-only // verification detached from its request. ErrSenderProofRequired = authkit.E(authkit.CodeSenderProofRequired) // ErrInvalidConfirmation rejects a `cnf` claim that is not exactly // {"x5t#S256": <unpadded base64url sha256>}. ErrInvalidConfirmation = authkit.E(authkit.CodeInvalidConfirmation) // ErrConfirmationWrongTokenType rejects `cnf` on any token type AuthKit does // not bind — accepting an unenforced binding would be a silent downgrade. ErrConfirmationWrongTokenType = authkit.E(authkit.CodeConfirmationWrongTokenType) )
RFC 8705 certificate-bound delegated tokens (ak#277). A `cnf.x5t#S256` claim is honoured only against the leaf certificate Go's TLS stack authenticated on THIS request; no header or context value can stand in.
var ErrLivenessUnconfigured = errors.New("verify: liveness gate used without a LivenessSource (call Verifier.WithLiveness)")
ErrLivenessUnconfigured is returned by VerifyRequestLive when no LivenessSource is wired. It is NOT a wire error: a missing source is a host wiring mistake, not a bad credential, and conflating the two would let a deployment that cannot check liveness look like one where every user is banned. RequiredLive refuses at construction so this can only be reached by an out-of-band caller.
Functions ¶
func Allow ¶ added in v0.71.0
func Allow(ctx context.Context, checker PermissionChecker, cl Claims, perm authkit.Perm, scope PermissionScope) (bool, error)
Allow checks machine permission ceilings against the exact UUID and authority issuer. Unbound delegated permissions retain their explicit issuer-trust contract. Human permissions always come from live assignments on GroupID. A missing or mismatched machine binding never falls back to human authority.
func NewSSRFGuardedClient ¶
NewSSRFGuardedClient returns a timeout-bounded *http.Client whose dialer resolves the target itself and refuses any private/reserved address, so a crafted jwks_uri (including DNS rebinding) can never reach internal services. WithSSRFGuard installs it on a Verifier.
func Optional ¶
Optional validates when Authorization is present; otherwise passes through. Gin hosts: use the gin-native authkitgin.Optional (adapters/gin) instead of hand-wrapping this.
func RequirePermission ¶ added in v0.65.0
func RequirePermission(checker PermissionChecker, perm authkit.Perm, resolve func(*http.Request) PermissionScope) func(http.Handler) http.Handler
RequirePermission authorizes the resolved group once and places that exact scope in the request context for the downstream handler. Missing resolution or any permission-check error denies. Unbound delegated authority is scope-free.
func Required ¶
Required validates the Bearer token (JWT), enforces iss/aud/exp, and stores claims in request context. Gin hosts: use the gin-native authkitgin.Required (adapters/gin) instead of hand-wrapping this.
func RequiredLive ¶ added in v0.92.0
RequiredLive is Required with the per-request account-liveness gate: a banned or deleted user is rejected on their NEXT request instead of at token expiry, and the downstream handler reads fresh identity claims.
It returns ErrLivenessUnconfigured when no LivenessSource is wired. A gate that cannot perform its check is a boot-time configuration error, refused before it reaches the route table rather than degraded to a weaker gate that looks like the stronger one.
func Sensitive ¶ added in v0.54.0
func Sensitive(options ...SensitiveOptions) func(http.Handler) http.Handler
func SensitiveClaims ¶ added in v0.54.0
func SensitiveClaims(cl Claims, options ...SensitiveOptions) bool
func WithPermissionScope ¶ added in v0.98.0
func WithPermissionScope(ctx context.Context, scope PermissionScope) context.Context
WithPermissionScope carries an already authorized scope into a trusted host adapter's handler. Call only after Allow/AllowLive succeeds; this does not authorize anything itself.
Types ¶
type Claims ¶
type Claims struct {
// Subject is an external access token's subject. It is meaningful only with
// Issuer; it never authorizes a lookup in the host's local user database.
Subject string
// UserID is populated only for an issuer explicitly trusted as IsLocal.
UserID string
Email string
EmailVerified bool
Username string
DiscordUsername string
SessionID string
// DeviceKeyID is the AuthKit-issued machine credential that minted this
// access token. It is present only on device-key tokens.
DeviceKeyID string
Roles []string
Entitlements []string
AMR []string
ACR string
AuthTime time.Time
TwoFAEnrollment bool
// MFAEnrolled reports whether the user has a usable second factor enrolled
// (claim `mfa_enrolled`, stamped at issue from MFAStatus.Satisfied). The
// Sensitive() gate uses it to require 2FA from users who have it, while never
// blocking users who don't.
MFAEnrolled bool
Issuer string
UserTier string
JTI string
// A delegated access token carries the external delegated subject in
// DelegatedSubject (claim `delegated_sub`). It never carries `sub` (UserID
// stays empty), so the local-user gate does not apply.
DelegatedSubject string
// Attributes carries opaque app-specific JSON inline. AuthKit transports
// these values; the consuming app owns their schema and semantics.
// Reserved well-known keys: `tier` (opaque entitlement-tier string, surfaced
// as UserTier) and `roles` (uuid array, surfaced as DelegatedRoles).
// `documents` is forbidden here because it is a top-level signed claim.
// Everything else is free-form per consuming app. Values are kept as raw
// JSON so the receiver decodes each into its own typed schema; nil when the
// claim is absent.
Attributes map[string]json.RawMessage
// DelegatedRoles are the delegated subject's role UUIDs carried by a
// delegated access token under `attributes.roles` (a JSON array of UUID strings). They are
// extracted and validated at verify (malformed entries dropped, count
// capped) and surfaced on DelegatedPrincipal.Roles. Downstream services use
// them as e.g. budget-scope keys; authkit treats them as opaque strings.
// Nil when absent. Distinct from the native-user Roles claim, which a
// delegated token never carries.
DelegatedRoles []string
// Documents is the validated top-level `documents` claim on a delegated
// token: versioned document type -> canonical content digest. Payload schema
// and authorization remain application-owned.
Documents map[string]string
// ConfirmationCertificateSHA256 is the RFC 8705 `cnf.x5t#S256` binding of a
// delegated token, already matched against the TLS peer leaf. Nil for an
// unbound token.
ConfirmationCertificateSHA256 *[32]byte
// TokenTyp is the JOSE `typ` header value. "access+jwt" identifies an
// AuthKit user access token; "delegated-access+jwt" identifies a delegated
// access token; "remote-application-access+jwt" identifies a remote
// application access token.
TokenTyp string
// TokenType marks the credential class. Empty for ordinary user JWTs;
// "api-key" for an API-key principal. An API-key principal carries
// Permissions but no UserID, so the live-user ban/enrichment gate is skipped
// (there is no user to look up).
TokenType string
// Permissions are the app-defined permission strings an API-key principal
// carries directly — the PBAC grant. Empty for user principals. authkit
// treats permission strings as opaque.
Permissions []string
// RemoteApplicationID / RemoteApplicationSlug identify the remote_application
// authenticated by a remote application access token. Populated ONLY for
// stored self or delegated claims, resolved server-side from the validated
// `iss` (never from a self-asserted token claim). The principal's Permissions
// carry its STORED, assigned authority.
RemoteApplicationID string
RemoteApplicationSlug string
// RemoteApplicationDomain / Tier / TrustRoot are the application's stored
// identity facts (#296), resolved server-side like ID: hosts authorize on
// an unclaimable identity (id, proven domain, root-registered issuer),
// never on the slug.
RemoteApplicationDomain string
RemoteApplicationTier string
RemoteApplicationTrustRoot string
// Machine authority is resolved live from the receiving AuthKit deployment.
// Names are presentation only; UUID and authority issuer fence ownership.
PermissionGroupID string
PermissionGroupAuthorityIssuer string
PermissionGroupPersona string
PermissionGroupInstance string
}
Claims is a typed view of authenticated user information attached by middleware.
func (Claims) Attribute ¶
func (c Claims) Attribute(key string) (json.RawMessage, bool)
Attribute returns one opaque JSON value and whether it is present.
func (Claims) AuthenticatedWithin ¶ added in v0.52.0
func (Claims) BoundToPermissionGroup ¶ added in v0.83.0
BoundToPermissionGroup reports whether these claims carry an owning permission-group binding (#248) — true for machine principals (API keys, remote-application access tokens) whose authority was resolved server-side from a specific group instance, including stored application delegation. Explicit platform delegation and user identity have no such binding.
func (Claims) Delegated ¶
func (c Claims) Delegated() (DelegatedPrincipal, bool)
Delegated returns the typed DelegatedPrincipal when the claims are delegated.
func (Claims) DelegatedAccess ¶
func (c Claims) DelegatedAccess() (DelegatedPrincipal, bool)
DelegatedAccess is the canonical accessor for a delegated access token's principal. It returns the typed DelegatedPrincipal and true only when the claims are a delegated access token (see IsDelegatedAccessToken).
func (Claims) DocumentReference ¶ added in v0.86.0
DocumentReference returns one validated typed document reference carried by these claims. It does not fetch or interpret the referenced payload.
func (Claims) HasEntitlement ¶
func (Claims) HasPermission ¶
HasPermission reports whether the claims carry a permission token covering the requested concrete permission.
func (Claims) IsDelegatedAccessToken ¶
IsDelegatedAccessToken reports whether these claims represent a delegated access token. The canonical signal is the `typ=delegated-access+jwt` JOSE header plus a delegated subject and no local user subject.
func (Claims) IsUser ¶ added in v0.72.0
IsUser reports whether these claims represent a native human user.
func (Claims) PermissionGroupAllows ¶ added in v0.83.0
func (c Claims) PermissionGroupAllows(scope PermissionScope) bool
PermissionGroupAllows compares immutable ownership. Missing binding fields on a machine principal deny; an old spelling cannot transfer authority.
func (Claims) Principal ¶ added in v0.72.0
Principal returns the small generic-auth shape for host adapters.
func (Claims) PrincipalKind ¶ added in v0.72.0
func (c Claims) PrincipalKind() authkit.PrincipalKind
PrincipalKind reports the broad credential class represented by these claims.
type DelegatedPrincipal ¶
type DelegatedPrincipal struct {
// PermissionGroup is the live stored application's authority boundary.
// Nil denotes explicitly trusted platform delegation. Missing fields in a
// non-nil scope must deny; they never imply unbound authority.
PermissionGroup *PermissionScope
// Issuer is the validated token issuer the receiving service trusts.
Issuer string
DelegatedSubject string
// Permissions are the resource-defined permission strings the receiving
// service authorizes against its own catalog. This is the authority source.
Permissions []string
// Attributes contains opaque, consumer-interpreted inline JSON values.
// Reserved keys: tier (UserTier), roles (Roles); documents is a separate
// top-level signed claim.
Attributes map[string]json.RawMessage
// Documents are exact typed signed-document references carried by the token.
Documents map[string]string
// ConfirmationCertificateSHA256 is the verified certificate binding; nil
// when the token is an unbound bearer.
ConfirmationCertificateSHA256 *[32]byte
// JTI is the token identifier (`jti` claim), when present.
JTI string
// UserTier is the resolved tier, sourced from `attributes.tier`.
UserTier string
// Roles are the actor's role UUID strings, sourced from `attributes.roles`
// (each validated as a well-formed UUID at verify; malformed entries are
// dropped, count is capped). Kept as strings so consumers parse to uuid
// without forcing a uuid dependency on the principal. Nil when absent.
Roles []string
}
DelegatedPrincipal is the identity carried by a delegated access token: an external actor (DelegatedSubject) whose authority is bounded by the VALIDATED Issuer plus Permissions. The subject does NOT exist as a local user in the validating service — authorization is by issuer trust plus Permissions, not local-user lookup.
func (DelegatedPrincipal) DocumentReference ¶ added in v0.86.0
func (p DelegatedPrincipal) DocumentReference(documentType string) (documents.Reference, bool)
type Enricher ¶
type Enricher interface {
ResolveAPIKeyDetailed(ctx context.Context, keyID, secret string) (authkit.ResolvedAPIKey, error)
GetRemoteApplication(ctx context.Context, issuer string) (*authkit.RemoteApplication, error)
ListEnabledRemoteApplications(ctx context.Context) ([]authkit.RemoteApplication, error)
ResolveRemoteApplicationAuthority(ctx context.Context, appID string) (authkit.RemoteApplicationAuthority, error)
}
Enricher resolves API keys and stored application authority. Local access tokens remain stateless; account liveness uses the separate LivenessSource.
type FederationStats ¶ added in v0.98.0
type FederationStats struct {
Snapshot int // enabled issuers in the last snapshot
SnapshotAt time.Time // when it was taken (zero: never)
Negative int // snapshot members whose registration recently failed
InFlight int // issuers currently being registered
}
FederationStats is a point-in-time view of the verifier's remote-application lazy-load state, for diagnostics and tests. Every count is bounded by the number of enabled remote applications, never by request traffic.
type IssuerOptions ¶
type IssuerOptions struct {
// JWKSURI is the URL to fetch JWKS from. If set, keys are fetched
// automatically and refreshed when they expire or an unknown kid appears.
JWKSURI string
// Keys are pre-provided public keys as PEM. The caller is responsible for
// refreshing by calling AddIssuer again with updated keys.
Keys []IssuerKey
// RawKeys are a static snapshot. Replace them by calling AddIssuer again.
RawKeys map[string]crypto.PublicKey
// PublicKeys reads live in-process keys on every verification, without
// caching or network requests. Use for a co-located rotating KeySource.
PublicKeys func() map[string]crypto.PublicKey
// CacheTTL controls how long fetched JWKS keys are considered fresh.
// Default: 10 minutes.
CacheTTL time.Duration
// MaxStale controls how long stale keys may be used as fallback after
// a failed JWKS refresh. Default: 1 hour.
MaxStale time.Duration
// IsLocal marks this issuer as the host application's own (first-party) token
// signer, as opposed to a remote_application/federated issuer. It guards the
// signing-key registry against a non-local registration overwriting the local
// issuer entry. Only this explicit trust may populate Claims.UserID.
IsLocal bool
// contains filtered or unexported fields
}
IssuerOptions configures how keys are obtained for an issuer. Use snapshot Keys/RawKeys, a JWKSURI, or the live PublicKeys provider. Keys/RawKeys may seed a JWKS cache for its configured CacheTTL.
type LivenessSource ¶ added in v0.92.0
type LivenessSource interface {
UserLivenessByIDs(ctx context.Context, ids []string) (map[string]authkit.UserLiveness, error)
}
LivenessSource resolves account liveness — and the identity fields that are fresh as of that same lookup — for verified user principals (#267). authkit.Client satisfies it, embedded or remote, so wiring is `v.WithLiveness(client)`; verify declares the port rather than importing the engine, exactly as it does for PermissionChecker.
type PermissionChecker ¶ added in v0.65.0
type PermissionChecker interface {
CanOnGroup(ctx context.Context, subject authkit.Subject, groupID string, perm authkit.Perm) (bool, error)
}
PermissionChecker checks live authority on an already resolved immutable group. Hosts resolve a name once at their request boundary and reuse its GroupID.
type PermissionScope ¶ added in v0.65.0
type PermissionScope struct {
GroupID string
AuthorityIssuer string
Persona authkit.Persona
Instance string
}
PermissionScope is a trusted request resolution. GroupID and AuthorityIssuer identify ownership; Persona and Instance describe its canonical public name.
func PermissionScopeFromContext ¶ added in v0.98.0
func PermissionScopeFromContext(ctx context.Context) (PermissionScope, bool)
PermissionScopeFromContext returns the exact group authorized by middleware, so a domain handler does not resolve the mutable path a second time.
type PermissionValidator ¶
PermissionValidator validates a delegated access token's `permissions` against the receiving service's own permissions. Return an error to reject the token. Called only for delegated access tokens.
type RemoteApplicationSource ¶
type RemoteApplicationSource interface {
ListEnabledRemoteApplications(ctx context.Context) ([]authkit.RemoteApplication, error)
// GetRemoteApplication fetches a SINGLE remote_application by its issuer,
// used after signature verification to resolve a service principal
// (remoteApplication). The lazy-load-on-miss path never calls it: it answers
// from the ListEnabledRemoteApplications snapshot (ak#297). *authkit.Service already
// implements this.
GetRemoteApplication(ctx context.Context, issuer string) (*authkit.RemoteApplication, error)
}
RemoteApplicationSource is the minimal store contract the Verifier needs to load remote_application principals (#74). *authkit.Service satisfies it. An embedding app may supply its own implementation in tests.
type SensitiveOptions ¶ added in v0.54.0
type ServiceJWTVerifyOption ¶
type ServiceJWTVerifyOption func(*serviceJWTVerifyConfig)
ServiceJWTVerifyOption configures VerifyServiceJWT.
func WithServiceJWTMaxLifetime ¶
func WithServiceJWTMaxLifetime(d time.Duration) ServiceJWTVerifyOption
WithServiceJWTMaxLifetime caps accepted service-JWT lifetime. Empty defaults to AuthKit's 15-minute service-JWT lifetime.
type Verifier ¶
type Verifier struct {
// contains filtered or unexported fields
}
Verifier validates JWTs from one or more issuers.
For verify-only mode, create with NewVerifier and add issuers via AddIssuer. For issuing mode, authhttp.Service creates a Verifier internally.
func NewVerifier ¶
func NewVerifier(opts ...VerifierOption) *Verifier
NewVerifier creates a new Verifier. Add trusted issuers via AddIssuer.
func (*Verifier) AddIssuer ¶
func (v *Verifier) AddIssuer(issuerID string, audiences []string, opts IssuerOptions) error
AddIssuer registers (or updates) a trusted issuer. This is the single method for adding any issuer — whether at startup or at runtime, whether keys come from a JWKS URL or are pre-provided.
func (*Verifier) AddMFAEnrollmentExemptRoutes ¶ added in v0.98.0
AddMFAEnrollmentExemptRoutes registers ANCHORED exempt paths (mount prefix + route path), matched exactly. authhttp.MountHandler calls it with the prefix it mounted under; once any anchored route is registered the suffix match of SetMFAEnrollmentExemptPaths is no longer consulted, so a host route that merely ends in "/user/2fa" cannot be reached with an enrollment-only token (ak#324). The suffix form remains for verify-only consumers that never mount.
func (*Verifier) AllowLive ¶ added in v0.92.0
func (v *Verifier) AllowLive(ctx context.Context, checker PermissionChecker, cl Claims, perm authkit.Perm, scope PermissionScope) (bool, error)
AllowLive is Allow with the account-liveness precondition: "this account is live AND holds perm", in one call.
It exists because both consumer hosts had independently written that conjunction by hand, each bolting a liveness lookup in front of verify.Allow — two gates a caller could get out of order, or forget one half of. A banned user who still holds a permission assignment must be denied, and that ordering is now the library's to guarantee, not the host's to remember.
Fail-closed throughout: a liveness error, a dead account, or a Can error all deny (the error is returned; callers must deny on a non-nil error).
func (*Verifier) FederationStats ¶ added in v0.98.0
func (v *Verifier) FederationStats() FederationStats
func (*Verifier) HTTPClient ¶
HTTPClient returns the outbound HTTP client the Verifier uses for JWKS fetches (the WithHTTPClient override, or the default timeout-bounded client).
func (*Verifier) HasLiveness ¶ added in v0.92.0
HasLiveness reports whether a LivenessSource is wired. Hosts that mount a liveness-gated route set conditionally can assert this at boot instead of discovering the gap on the first request.
func (*Verifier) IsLive ¶ added in v0.92.0
IsLive reports whether cl's principal is a live account, and returns the fresh identity fields alongside the verdict. It is the programmatic predicate behind VerifyRequestLive, for gates that already hold verified Claims and are not driving an HTTP pipeline.
Non-user principals (no UserID) are live by definition here — their liveness lives on their own credential — and come back with a zero UserLiveness. Fail-closed: an error, or an id the directory does not return, is false.
func (*Verifier) LoadRemoteApplications ¶
func (v *Verifier) LoadRemoteApplications(ctx context.Context, src RemoteApplicationSource, audiences []string) error
LoadRemoteApplications registers enabled store-managed issuers and removes entries no longer in the enabled set. Every verification also reads the live row for eligibility and key-source changes; callers need not reload for key rotation or revocation. Explicit AddIssuer registrations are not reconciled. A nil source uses the backend installed by WithService.
func (*Verifier) RemoveIssuer ¶
RemoveIssuer removes a previously added issuer.
func (*Verifier) SetMFAEnrollmentExemptPaths ¶ added in v0.79.0
SetMFAEnrollmentExemptPaths installs the set of route paths that stay reachable to a request blocked by the requireMFAEnrollment gate or carrying a TwoFAEnrollment-only token (#243): the 2FA enroll/challenge/verify surface. AuthKit's server derives this set from its authoritative route registry (authhttp.RouteSpec.MFAEnrollmentExempt) at construction, so a renamed or added enroll route can't silently drift out of the allowlist. A Verifier that never calls this (verify-only, no WithRequireMFAEnrollment) exempts nothing. Paths are suffix-matched against the incoming request path, since AuthKit routes are prefix-neutral (a host may mount them under any prefix).
func (*Verifier) SetRemoteApplicationSource ¶
func (v *Verifier) SetRemoteApplicationSource(src RemoteApplicationSource)
SetRemoteApplicationSource overrides the federation source consulted by the lazy-load-on-miss path (keyForToken). LoadRemoteApplications is the normal way to set it; this is the explicit seam for tests and advanced wiring.
func (*Verifier) ValidateDocumentIssuer ¶ added in v0.86.0
ValidateDocumentIssuer performs the resolver's pre-network trust check. A registered issuer is accepted; a configured remote-application source gets the same bounded lazy-load-on-first-use behavior as token verification.
func (*Verifier) Verify ¶
Verify parses + verifies a token and returns typed Claims. It enforces issuer/audience/expiry with the configured skew, plus authkit's user-token invariant, on top of VerifyClaims. ctx bounds every key lookup the verification needs (JWKS fetch, lazy issuer load, remote-application resolution); a cancelled ctx aborts them. It is detached from any request, so a certificate-bound delegated token (cnf) fails with ErrSenderProofRequired here; verify those through VerifyRequest.
func (*Verifier) VerifyClaims ¶
VerifyClaims verifies signature, issuer eligibility, audience and exp/nbf/iat, returning raw claims for host-defined token profiles. It does not enforce AuthKit token type, subject, permission or sender-proof semantics. Hosts must enforce their custom profile; use Verify or VerifyRequest for AuthKit access tokens. A store-managed issuer always requires a live enabled application row.
func (*Verifier) VerifyDelegatedAccess ¶
func (v *Verifier) VerifyDelegatedAccess(ctx context.Context, tokenStr string) (Claims, DelegatedPrincipal, error)
VerifyDelegatedAccess verifies a token, requires it to be a delegated access token, and runs any configured permission/attributes validators. It returns the typed Claims and the DelegatedPrincipal. Use it on resource servers that only accept delegated access tokens and want catalog/policy enforcement.
func (*Verifier) VerifyDelegatedAccessRequest ¶ added in v0.98.0
func (v *Verifier) VerifyDelegatedAccessRequest(r *http.Request) (Claims, DelegatedPrincipal, error)
VerifyDelegatedAccessRequest is VerifyDelegatedAccess bound to the request's bearer token and TLS peer certificate, the only path that accepts a certificate-bound (cnf) delegated token.
func (*Verifier) VerifyDocument ¶ added in v0.86.0
func (v *Verifier) VerifyDocument(ctx context.Context, document documents.SignedDocument, expected documents.VerifyOptions) (documents.Envelope, error)
VerifyDocument verifies exact-byte digest, strict envelope metadata, trusted issuer/key resolution, JOSE profile, and signature. It never decodes the application-owned Envelope.Payload.
func (*Verifier) VerifyRequest ¶ added in v0.65.0
VerifyRequest runs the full Required authentication pipeline — bearer parse, API-key resolution, typed JWT verification and the 2FA gate — and returns claims without writing a response. Issuer eligibility and delegated authority are enforced by the shared verifier on every typed entrypoint. Embedders that authenticate a request outside the middleware chain call this instead of driving Required against a throwaway ResponseWriter. The native-user path is stateless: it does ZERO DB lookups (#215) — no ban gate, no role/email/provider re-enrichment. Ban/deleted is enforced at token mint (login + refresh); the short access TTL bounds the residual window (#90).
That statelessness is now an explicit OPT-OUT, not the only option (#267): a privileged surface that cannot accept the residual window calls VerifyRequestLive (or mounts RequiredLive) and gets the same pipeline plus a per-request account-liveness gate and fresh identity claims. Choose this one deliberately — for genuinely stateless verifiers, and for read paths where a ≤1-TTL window is acceptable.
func (*Verifier) VerifyRequestLive ¶ added in v0.92.0
VerifyRequestLive is VerifyRequest plus a per-request account-liveness gate: the stateful twin of the deliberately stateless default (#215/#267).
It exists because the stateless path leaves a banned or deleted user holding a syntactically valid token until it expires, and every privileged host surface was hand-rolling the same gate around VerifyRequest to close that window — one of them calling the ADMIN directory per request just to refresh a username and email onto the claims. Both of those are this method's job now.
Behaviour:
- Everything VerifyRequest enforces (bearer parse, API-key resolution, JWT verify, 2FA gates, the delegated issuer gate) runs first, unchanged.
- Only NATIVE USER principals are liveness-checked. An API key resolves its secret live on every request already, and a delegated principal is gated on its remote application being enabled; neither carries a UserID, and inventing a lookup for them would be a second gate, not a stronger one.
- FAIL-CLOSED is the only posture. A lookup error, an id the directory does not return, or a not-Allowed verdict all deny with 401. There is no option to fall back to the stateless answer: a gate that opens when its dependency is down is not a gate.
- The returned Claims carry the FRESH Username, Email and EmailVerified from that same lookup, overwriting whatever the token minted — including overwriting with empty, which is the honest answer for a user who cleared the field. This is what makes a host's per-request AdminGetUser call deletable. Roles and entitlements are deliberately NOT re-enriched here: they already have live reads of their own (RoleSlugsByUsers, Allow, ListEntitlements) and a second copy would be the duplication this issue is removing, not another one of it.
CACHING CONTRACT: none. Exactly one UserLivenessByIDs call per gated request, no memoization, no negative cache. That is not a regression — the hosts this replaces each did one lookup per request — and it is the only version of the contract that can be stated honestly, because any cache reintroduces exactly the stale-authorization window the gate exists to close. A deployment that decides it wants that trade implements LivenessSource itself and owns the staleness window explicitly, rather than inheriting one from a library default.
Compose with permission checks rather than duplicating them: this answers "is this account live", RequirePermission/Allow answer "may it do this".
func (*Verifier) VerifyServiceJWT ¶
func (v *Verifier) VerifyServiceJWT(ctx context.Context, tokenStr string, opts ...ServiceJWTVerifyOption) (authkit.ServiceJWTClaims, error)
VerifyServiceJWT verifies a first-party OIDC service JWT through the verifier's registered issuer/JWKS store and returns the requested permissions. AuthKit does not grant those permissions; the host must intersect them with server-side grants for the issuer/subject/resource.
func (*Verifier) WithLiveness ¶ added in v0.92.0
func (v *Verifier) WithLiveness(src LivenessSource) *Verifier
WithLiveness wires the account-liveness backend used by VerifyRequestLive and the RequiredLive middlewares. Pass the authkit.Client the host already holds.
func (*Verifier) WithService ¶
WithService installs the API-key/application backend and default lazy source. Explicit AddIssuer entries retain their configured trust; stored entries are loaded through LoadRemoteApplications or lazy discovery, never AddIssuer.
type VerifierOption ¶
type VerifierOption func(*Verifier)
VerifierOption configures a Verifier.
func WithAPIKeyPrefix ¶
func WithAPIKeyPrefix(prefix string) VerifierOption
WithAPIKeyPrefix sets the host application's API-key brand prefix used to detect opaque shared-secret API keys in the middleware. Empty -> bare "st_".
func WithAlgorithms ¶
func WithAlgorithms(algs ...string) VerifierOption
WithAlgorithms REPLACES the allowed JWS algorithm set; it does not add to it.
The default is ["RS256", "ES256", "ES384", "ES512", "EdDSA"], not ["RS256"]. The breadth is deliberate: federated and remote-application issuers legitimately sign with EC or Ed25519 keys and must verify out of the box. Narrow it only if you control every issuer this Verifier accepts.
The list is a pure allow-list checked in resolveIssuer, so "none" and the symmetric HS* algorithms are absent from the default and rejected there. A caller who adds them anyway does not open an algorithm-confusion hole: authkit only ever hands the parser an asymmetric public key, which golang-jwt's HMAC and none signing methods refuse as the wrong key type.
Passing an empty list rejects every token (fail closed).
func WithHTTPClient ¶
func WithHTTPClient(c *http.Client) VerifierOption
WithHTTPClient sets the HTTP client used for JWKS fetching.
func WithPermissions ¶
func WithPermissions(fn PermissionValidator) VerifierOption
WithPermissions installs a validator that every typed verification path runs against the token's `permissions`. Use it to ensure every permission string belongs to this resource server's permissions.
func WithRemoteApplicationAudiences ¶ added in v0.98.0
func WithRemoteApplicationAudiences(audiences ...string) VerifierOption
WithSkew sets the clock skew tolerance for exp/nbf/iat checks. Default: 60s. WithRemoteApplicationAudiences sets the audiences a lazily-loaded remote application issuer is registered with on the resolveIssuer miss path when the host never calls LoadRemoteApplications (which overrides it). NewServer passes Config.Token.ExpectedAudiences so both load paths enforce the same audience (ak#324).
func WithRequireMFAEnrollment ¶ added in v0.72.0
func WithRequireMFAEnrollment(require bool) VerifierOption
WithRequireMFAEnrollment enables the per-request forced-enrollment gate (#148): when 2FA policy is Required, a native-user request whose token shows the user is not yet enrolled (mfa_enrolled absent) is rejected with 2fa_enrollment_required unless it targets a 2FA enroll/challenge route. This makes Required gate the SESSION — every existing un-enrolled user is challenged on their next request, not just new signups. Set by the AuthKit server from TwoFactor.Mode; verify-only resource servers leave it off.
func WithSSRFGuard ¶
func WithSSRFGuard() VerifierOption
WithSSRFGuard installs NewSSRFGuardedClient as the JWKS client: DNS is resolved first and any private/reserved answer is refused. Use it on Verifiers that fetch JWKS from user-registered (remote_application) issuers.
func WithSkew ¶
func WithSkew(d time.Duration) VerifierOption