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 ¶
- func AuthErrorFromContext(ctx context.Context) error
- func ClaimsFromContext(ctx context.Context) (jwt.MapClaims, bool)
- func IsOperator(ctx context.Context) bool
- func Middleware(cfg Config, store *policy.Store, logger *slog.Logger) (func(http.Handler) http.Handler, error)
- func RoleFromContext(ctx context.Context) string
- func WithAuthError(ctx context.Context, err error) context.Context
- func WithClaims(ctx context.Context, claims jwt.MapClaims) context.Context
- func WithOperator(ctx context.Context) context.Context
- func WithRole(ctx context.Context, role string) context.Context
- type Config
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AuthErrorFromContext ¶
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 ¶
ClaimsFromContext extracts JWT claims from the request context. ok is false when no valid token established claims.
func IsOperator ¶
IsOperator reports whether the request was authenticated with the operator key. See WithOperator.
func Middleware ¶
func Middleware(cfg Config, store *policy.Store, logger *slog.Logger) (func(http.Handler) http.Handler, error)
Middleware authenticates Bearer tokens and records the caller's role, claims, and any validation error in the request context. Authentication is decoupled from authorization: this middleware NEVER rejects a request and writes no response. A missing token, a token with no role claim, or an invalid/expired/malformed token all yield an EMPTY role, which downstream gates resolve to the policy default_role. When a present token fails to validate, the (sanitized) error is stashed in the context so a gate that later denies the request can fail loud rather than silently treating the caller as the public default.
Verification is JWKS-or-HMAC, not both: when JWKSURL is configured (and initializes) JWKS is the sole verifier and the HMAC secret is ignored; otherwise the HMAC secret (JWTSecret) is used. Accepted signing algorithms are restricted to the active verifier's family (asymmetric for JWKS, HMAC otherwise) so a token can't force an alg-confusion or alg:none bypass. With neither JWKSURL nor JWTSecret configured, no token can validate and every request falls back to the default role — i.e. a pure public deployment.
If JWKSURL is set but its JWK Set can't be fetched at startup, Middleware returns an error so the caller can fail fast instead of booting into a degraded state where no token can validate.
When cfg.OperatorKey is set, a non-JWT operator path is checked before the Bearer token (see operatorKey below): a constant-time match on the presented credential authorizes a full-access platform operator independent of the JWT verifier. store and logger back that path — the live admin role is read from store per request, and operator authentications are logged at info (audit). A presented credential that does not match is logged at warn and counted by wavehouse_auth_operator_key_failures_total (a probing signal), then falls through like any unauthenticated request. Both store and logger may be nil when no operator key is configured.
func RoleFromContext ¶
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 ¶
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 ¶
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 ¶
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/deleted — so it is the break-glass path for restoring a wiped policy over HTTP.
Types ¶
type Config ¶
type Config struct {
JWTSecret string
JWKSURL string
RoleClaim string // dot-separated claim path, e.g. "role" or "app_metadata.role"
OperatorKey string // 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)
}
Config holds configuration for the JWT authentication middleware.