feat(httpauth): initial release — provider-agnostic HTTP auth middleware

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.
This commit is contained in:
2026-05-07 21:37:25 -06:00
commit 18e5a16f7e
16 changed files with 879 additions and 0 deletions

39
claims_provider.go Normal file
View File

@@ -0,0 +1,39 @@
package httpauth
import (
"context"
"code.nochebuena.dev/go/rbac"
)
type claimsPermissionProvider struct {
claimsKey string
}
// NewClaimsPermissionProvider returns an rbac.PermissionProvider that reads
// pre-computed permission masks from JWT claims stored in the request context
// by SetTokenData. Expects claims[claimsKey] to be a map[string]any where each
// key is a resource name and the value is the bitmask as int64 or float64
// (JSON unmarshaling decodes numbers as float64).
// Returns 0 without error if the claim is absent — callers treat 0 as no access.
func NewClaimsPermissionProvider(claimsKey string) rbac.PermissionProvider {
return &claimsPermissionProvider{claimsKey: claimsKey}
}
func (p *claimsPermissionProvider) ResolveMask(ctx context.Context, _, resource string) (rbac.PermissionMask, error) {
claims, ok := getClaims(ctx)
if !ok {
return 0, nil
}
permisos, ok := claims[p.claimsKey].(map[string]any)
if !ok {
return 0, nil
}
switch v := permisos[resource].(type) {
case int64:
return rbac.PermissionMask(v), nil
case float64:
return rbac.PermissionMask(int64(v)), nil
}
return 0, nil
}