Provides SetTokenData for upstream AuthMiddleware implementations, EnrichmentMiddleware and AuthzMiddleware compatible with any provider that calls SetTokenData, ClaimsPermissionProvider for JWT-embedded permissions, and CachedPermissionProvider for TTL-backed runtime resolution via any Cache implementation.
4.8 KiB
httpauth
Provider-agnostic HTTP middleware for identity enrichment and RBAC authorization.
Purpose
httpauth is the shared foundation for all httpauth-* provider modules. It provides
EnrichmentMiddleware, AuthzMiddleware, two rbac.PermissionProvider implementations
(ClaimsPermissionProvider and CachedPermissionProvider), and SetTokenData — the
bridge between a provider-specific AuthMiddleware and the rest of the auth stack.
Any AuthMiddleware that calls SetTokenData after token verification is compatible.
Downstream code reads identity exclusively via rbac.FromContext — no provider type
leaks past the middleware boundary.
Tier & Dependencies
Tier: 3 (transport auth layer; depends only on Tier 0 rbac; no external SDK)
Module: code.nochebuena.dev/go/httpauth
Direct imports: code.nochebuena.dev/go/rbac only
httpauth does not import logz, httpmw, httputil, Firebase, or any JWT library.
It has no logger parameter — errors are returned as HTTP responses.
Key Design Decisions
rbac.PermissionProviderwithout redefinition:AuthzMiddlewareacceptsrbac.PermissionProviderdirectly.rbacis the single source of truth for this interface. Provider-specific modules (e.g.httpauth-firebase) previously defined their ownPermissionProviderlocally — that duplication is removed.SetTokenDataas the integration contract: Provider-specificAuthMiddlewareimplementations callSetTokenData(ctx, uid, claims)after verifying the token. The context keys are unexported typed structs.EnrichmentMiddlewarereads them via the unexported helpersgetUIDandgetClaimsin the same package.- Two permission strategies:
ClaimsPermissionProvider(JWT-embedded, no DB call) andCachedPermissionProvider(TTL-backed runtime resolution) are first-class implementations. Choose based on token size and revocation requirements. - Cache falls through on error:
CachedPermissionProvidertreats cache errors as misses — a cache outage degrades gracefully to the inner provider.
Patterns
Full stack with self-issued JWT:
r.Use(jwtauth.AuthMiddleware(signer, publicPaths, nil))
r.Use(httpauth.EnrichmentMiddleware(myEnricher, httpauth.WithTenantHeader("X-Tenant-ID")))
// Simple app — permissions embedded in JWT:
claimsProvider := httpauth.NewClaimsPermissionProvider("permisos")
r.With(httpauth.AuthzMiddleware(claimsProvider, "usuarios", rbac.Permission(1))).
Get("/usuarios", handler)
// Complex app — runtime resolution with cache:
cachedProvider := httpauth.NewCachedPermissionProvider(dbProvider, valkeyCache, 5*time.Minute)
r.With(httpauth.AuthzMiddleware(cachedProvider, "usuarios", rbac.Permission(1))).
Get("/usuarios", handler)
Provider-specific AuthMiddleware calling SetTokenData:
// Inside httpauth-jwt or httpauth-firebase AuthMiddleware, after token verification:
ctx := httpauth.SetTokenData(r.Context(), verified.UID, verified.Claims)
next.ServeHTTP(w, r.WithContext(ctx))
Reading identity in a handler:
identity, ok := rbac.FromContext(r.Context())
if !ok {
// should not happen if EnrichmentMiddleware is in the chain
}
Implementing Cache (e.g. with Valkey):
type valkeyCache struct{ client valkey.Client }
func (c *valkeyCache) Get(ctx context.Context, key string) (int64, bool, error) { ... }
func (c *valkeyCache) Set(ctx context.Context, key string, val int64, ttl time.Duration) error { ... }
Cache key for manual invalidation: rbac:{uid}:{resource}
What to Avoid
- Do not call
SetTokenDatafrom application or domain layer code. It is the exclusive responsibility of provider-specificAuthMiddlewareimplementations. - Do not put
AuthzMiddlewarebeforeEnrichmentMiddlewarein the chain.AuthzMiddlewarereadsrbac.Identityfrom context; if enrichment has not run, it will return 401. - Do not import
httpauthfrom service or domain layers. It is a transport package. - Do not define a local
PermissionProviderinterface in provider modules that import this package — userbac.PermissionProviderdirectly.
Testing Notes
compliance_test.goverifies at compile time that mock types satisfyIdentityEnricherandCache, and thatrbac.PermissionProvideris satisfied by the two built-in provider implementations.EnrichmentMiddlewaretests useinjectTokenData(uid, claims, next)— a helper that callsSetTokenDatato bypass a real upstreamAuthMiddleware.AuthzMiddlewaretests pre-populate context withrbac.SetInContext— no enrichment middleware needed.ClaimsPermissionProvidertests exercise bothfloat64(JSON decode) andint64paths for the mask value.CachedPermissionProvidertests exercise cache hit, miss, cache error fallthrough, and inner provider error propagation.