auth

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 13, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package auth handles authentication: it validates JWT Bearer tokens and records the caller's role, claims, and any token-validation error in the request context. It makes no authorization decisions and writes no HTTP responses — authorization lives in internal/policy (role checks) and the gates in internal/api (which translate decisions into HTTP responses).

Index

Constants

This section is empty.

Variables

View Source
var ErrVerifierPending = errors.New("token verifier not ready: the tenant's JWKS has not been fetched yet")

ErrVerifierPending is the auth error stashed for a token that could not be checked because its tenant's JWKS has not been fetched yet — at boot, or after a reload changed the tenant's jwks_url or role_claim (either rebuilds the verifier, fetch included). Distinct from an invalid token on purpose: the token may well be good, so the tenant route answers 503 + Retry-After (api) rather than evaluate the request under the policy default_role, which could accept its data under a lesser role while another pod holding the keys would have served it properly.

Functions

func AuthErrorFromContext

func AuthErrorFromContext(ctx context.Context) error

AuthErrorFromContext returns the token-validation error recorded when a present token failed to validate (bad signature, malformed, expired). It is nil for a valid token or for no token at all. Gates use it to fail loud — surfacing the token problem instead of a bare "forbidden" — when a request that fell back to the default role is denied for lacking permission.

func ClaimsFromContext

func ClaimsFromContext(ctx context.Context) (jwt.MapClaims, bool)

ClaimsFromContext extracts JWT claims from the request context. ok is false when no valid token established claims.

func IsOperator

func IsOperator(ctx context.Context) bool

IsOperator reports whether the request was authenticated with the operator key. See WithOperator.

func RoleFromContext

func RoleFromContext(ctx context.Context) string

RoleFromContext extracts the role string from the request context. An empty string means no role was established — no token, a token without a role claim, or an invalid/expired token — which callers resolve to the policy default_role via policy.ResolveRole.

func WithAuthError

func WithAuthError(ctx context.Context, err error) context.Context

WithAuthError returns a copy of ctx carrying a token-validation error, used by gates to fail loud when a request that fell back to the default role is denied. See AuthErrorFromContext.

func WithClaims

func WithClaims(ctx context.Context, claims jwt.MapClaims) context.Context

WithClaims returns a copy of ctx carrying the given JWT claims. Set by the middleware; exported so tests (and any code constructing an authenticated context) can establish identity.

func WithOperator

func WithOperator(ctx context.Context) context.Context

WithOperator returns a copy of ctx marked as a platform-operator request, set by the middleware when a valid operator key is presented (Authorization: Operator <key>, or the X-Operator-Key alias). The operator bit authorizes the admin surface independently of the policy — RequireAdmin honors it even when the policy is nil (policies.json empty) — so it is the break-glass path that keeps the admin surface reachable while locked out (trigger a reload after fixing the files).

func WithRole

func WithRole(ctx context.Context, role string) context.Context

WithRole returns a copy of ctx carrying the given role string.

Types

type Authenticator added in v0.2.0

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

Authenticator owns one verifier per tenant behind the middleware, so a settings reload can replace a tenant's without restarting: Reconfigure builds a new verifier from the tenant's adopted wiring and swaps it in when that wiring changed, keeping the one it has when it did not; Prune drops the verifiers of tenants that stopped being served, rejected or removed; Close stops every JWKS refresh. The operator key is boot config and never changes.

func NewAuthenticator added in v0.2.0

func NewAuthenticator(cfg Config, tenantOf TenantSource, policies PolicySource) *Authenticator

NewAuthenticator builds an Authenticator with no verifier yet: the caller adds one per tenant with Reconfigure. tenantOf names the request's tenant; nil reads every request as tenant.Default (a single-tenant test). policies backs the operator-key path (the admin role it stamps is the request tenant's) and may be nil when no operator key is configured.

func (*Authenticator) Close added in v0.2.0

func (a *Authenticator) Close()

Close stops every verifier's JWKS refresh. The middleware then fails closed for every tenant; it is not meant to be served past this.

func (*Authenticator) Middleware added in v0.2.0

func (a *Authenticator) Middleware() func(http.Handler) http.Handler

Middleware returns the http middleware bound to this Authenticator; it reads the request tenant's current verifier on every request.

func (*Authenticator) Prune added in v0.2.0

func (a *Authenticator) Prune(served func(tenant.ID) bool)

Prune drops the verifier of every tenant served does not vouch for — the tenants a reload removed or rejected — and stops their JWKS refresh: a tenant that is not being served has no work running for it, and one that is adopted again is rebuilt, fetch and all, by Reconfigure.

func (*Authenticator) Reconfigure added in v0.2.0

func (a *Authenticator) Reconfigure(id tenant.ID, w Wiring)

Reconfigure gives tenant id a verifier built from w, replacing the one it has when w changed — the adopted settings are the authority, so the swap does not depend on a JWKS fetch succeeding (see newVerifier) — and keeping it, refresh and all, when w did not. The replaced verifier's JWKS refresh is stopped.

type Config

type Config struct {
	// OperatorKey is the optional non-JWT operator credential; a match on
	// the presented credential (Authorization: Operator <key>, or the
	// X-Operator-Key alias) authorizes a full-access platform operator (see
	// Middleware).
	OperatorKey string
}

Config is the boot-config half of authentication: the platform's own credential, fixed for the process lifetime and shared by every tenant.

type PolicySource added in v0.2.0

type PolicySource func(tenant.ID) *policy.Policy

PolicySource yields a tenant's access-control policy, read per request so a settings reload applies to the next one. nil for a tenant that is not being served — the ops tree over a nested directory with no tenant 0, where the gate reads no policy either.

type TenantSource added in v0.2.0

type TenantSource func(context.Context) (tenant.ID, bool)

TenantSource names the tenant a request resolved to — the store api.TenantMW put in the context, and its Tenant() — and false on a tenant-exempt route, where none was resolved.

type Wiring added in v0.2.0

type Wiring struct {
	JWKSURL string
	// JWTSecret is the HMAC secret, the verifier when JWKSURL is empty; a
	// tenant's own, so a reload that rotates it rebuilds the verifier.
	JWTSecret string
	RoleClaim string // dot-separated claim path, e.g. "role" or "app_metadata.role"
}

Wiring is one tenant's half: the verifier wiring its settings directory's auth block carries, adopted per tenant (Authenticator.Reconfigure).

Jump to

Keyboard shortcuts

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