httpauth

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: MIT Imports: 5 Imported by: 0

README

httpauth

Provider-agnostic HTTP middleware for identity enrichment and RBAC authorization.

Overview

Three composable func(http.Handler) http.Handler middleware functions and two rbac.PermissionProvider implementations:

Component Responsibility
EnrichmentMiddleware Calls app-provided IdentityEnricher; stores rbac.Identity in context
AuthzMiddleware Resolves permission mask via rbac.PermissionProvider; gates request
ClaimsPermissionProvider Reads pre-computed masks from JWT claims — no DB call
CachedPermissionProvider Wraps any provider with a TTL cache; falls through on miss or error
SetTokenData Injects uid + claims from any verified token into the request context

Any upstream AuthMiddleware that calls SetTokenData is compatible — Firebase, self-issued JWT, API key, etc.

Installation

require code.nochebuena.dev/go/httpauth v0.1.0

Usage

With JWT-embedded permissions (simple apps)
// Auth middleware (e.g. httpauth-jwt) calls httpauth.SetTokenData after verification.
// JWT claims include: { "permisos": { "usuarios": 515, "roles": 6 } }

r.Use(jwtauth.AuthMiddleware(signer, publicPaths, nil))
r.Use(httpauth.EnrichmentMiddleware(myEnricher))

claimsProvider := httpauth.NewClaimsPermissionProvider("permisos")
r.With(httpauth.AuthzMiddleware(claimsProvider, "usuarios", rbac.Permission(1))).
    Get("/usuarios", handler)
With runtime resolution + cache (complex apps)
r.Use(jwtauth.AuthMiddleware(signer, publicPaths, nil))
r.Use(httpauth.EnrichmentMiddleware(myEnricher, httpauth.WithTenantHeader("X-Tenant-ID")))

dbProvider := myapp.NewDBPermissionProvider(db)
cachedProvider := httpauth.NewCachedPermissionProvider(dbProvider, valkeyCache, 5*time.Minute)

r.With(httpauth.AuthzMiddleware(cachedProvider, "usuarios", rbac.Permission(1))).
    Get("/usuarios", handler)

Interfaces

IdentityEnricher
type IdentityEnricher interface {
    Enrich(ctx context.Context, uid string, claims map[string]any) (rbac.Identity, error)
}

Implement in your application to load user data and return an rbac.Identity.

Cache
type Cache interface {
    Get(ctx context.Context, key string) (int64, bool, error)
    Set(ctx context.Context, key string, value int64, ttl time.Duration) error
}

Implement with Valkey, Redis, or any in-memory store. Cache keys follow the format rbac:{uid}:{resource}.

rbac.PermissionProvider (from the rbac package)
type PermissionProvider interface {
    ResolveMask(ctx context.Context, uid, resource string) (rbac.PermissionMask, error)
}

AuthzMiddleware accepts any implementation — ClaimsPermissionProvider, CachedPermissionProvider, or your own.

SetTokenData

func SetTokenData(ctx context.Context, uid string, claims map[string]any) context.Context

Called by provider-specific AuthMiddleware implementations after token verification. EnrichmentMiddleware reads the injected values automatically.

Options

Option Description
WithTenantHeader(header) Reads TenantID from the named request header. If absent, TenantID remains "".

HTTP status codes

Condition Status
No uid in context (EnrichmentMiddleware) 401
Enricher error 500
No rbac.Identity in context (AuthzMiddleware) 401
Permission denied or provider error 403

Cache key format

CachedPermissionProvider uses rbac:{uid}:{resource} as the cache key. To invalidate manually, delete the key directly via your Cache implementation.

Documentation

Overview

Package httpauth provides provider-agnostic HTTP middleware for identity enrichment and RBAC authorization.

Any upstream AuthMiddleware that calls SetTokenData to inject uid and claims into the request context is compatible with this package — Firebase, self-issued JWT, API key, etc.

Typical middleware chain:

r.Use(jwtauth.AuthMiddleware(signer, publicPaths, nil))
r.Use(httpauth.EnrichmentMiddleware(userEnricher, httpauth.WithTenantHeader("X-Tenant-ID")))

// Choose one PermissionProvider:
claimsProvider := httpauth.NewClaimsPermissionProvider("permisos")   // JWT-embedded
cachedProvider := httpauth.NewCachedPermissionProvider(db, cache, ttl) // runtime + cache

r.With(httpauth.AuthzMiddleware(provider, "orders", rbac.Permission(1))).
    Post("/orders", handler)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AuthzMiddleware

func AuthzMiddleware(provider rbac.PermissionProvider, resource string, required rbac.Permission) func(http.Handler) http.Handler

AuthzMiddleware reads the rbac.Identity from context (set by EnrichmentMiddleware) and gates the request against the required permission on resource. Uses rbac.PermissionProvider directly — no local redefinition of the interface. Returns 401 if no identity is in context. Returns 403 if the identity lacks the required permission or if the provider errors.

func EnrichmentMiddleware

func EnrichmentMiddleware(enricher IdentityEnricher, opts ...EnrichOpt) func(http.Handler) http.Handler

EnrichmentMiddleware reads uid + claims injected by any upstream AuthMiddleware via SetTokenData, calls enricher.Enrich, and stores the resulting rbac.Identity in context via rbac.SetInContext. Returns 401 if no uid is present (SetTokenData was not called upstream). Returns 500 if the enricher fails.

func NewCachedPermissionProvider

func NewCachedPermissionProvider(inner rbac.PermissionProvider, cache Cache, ttl time.Duration) rbac.PermissionProvider

NewCachedPermissionProvider wraps inner with a TTL-based cache layer. Cache key format: "rbac:{uid}:{resource}". On cache miss, falls through to inner and populates the cache. On cache error, falls through to inner silently — never fails due to cache unavailability. For explicit invalidation, delete "rbac:{uid}:{resource}" directly via your Cache.

func NewChainPermissionProvider added in v1.0.0

func NewChainPermissionProvider(providers ...rbac.PermissionProvider) rbac.PermissionProvider

NewChainPermissionProvider returns an rbac.PermissionProvider that tries each provider in order and returns the first non-zero mask. If all providers return 0, the result is 0. On error from any provider, the error is propagated immediately and subsequent providers are not consulted.

Primary use case: JWT claims fast-path with DB fallback.

chain := httpauth.NewChainPermissionProvider(
    httpauth.NewClaimsPermissionProvider("permisos"), // JWT claims — no DB call
    httpauth.NewCachedPermissionProvider(dbProvider, cache, 5*time.Minute), // fallback
)

func NewClaimsPermissionProvider

func NewClaimsPermissionProvider(claimsKey string) rbac.PermissionProvider

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 SetTokenData

func SetTokenData(ctx context.Context, uid string, claims map[string]any) context.Context

SetTokenData injects a verified uid and raw claims into the context. Called by provider-specific AuthMiddleware implementations after token verification. EnrichmentMiddleware reads these values automatically via unexported helpers.

Types

type Cache

type Cache interface {
	Get(ctx context.Context, key string) (int64, bool, error)
	Set(ctx context.Context, key string, value int64, ttl time.Duration) error
}

Cache abstracts the caching backend for permission masks. Implementations are typically backed by Valkey or Redis.

type EnrichOpt

type EnrichOpt func(*enrichConfig)

EnrichOpt configures EnrichmentMiddleware.

func WithTenantHeader

func WithTenantHeader(header string) EnrichOpt

WithTenantHeader configures the request header from which TenantID is read. If the header is absent on a request, TenantID remains "" — no error is returned.

type IdentityEnricher

type IdentityEnricher interface {
	Enrich(ctx context.Context, uid string, claims map[string]any) (rbac.Identity, error)
}

IdentityEnricher builds an rbac.Identity from verified token data. The application provides the implementation — typically reads from a user store.

Jump to

Keyboard shortcuts

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