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.
113 lines
3.5 KiB
Markdown
113 lines
3.5 KiB
Markdown
# 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)
|
|
|
|
```go
|
|
// 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)
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
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)
|
|
|
|
```go
|
|
type PermissionProvider interface {
|
|
ResolveMask(ctx context.Context, uid, resource string) (rbac.PermissionMask, error)
|
|
}
|
|
```
|
|
|
|
`AuthzMiddleware` accepts any implementation — `ClaimsPermissionProvider`, `CachedPermissionProvider`, or your own.
|
|
|
|
## SetTokenData
|
|
|
|
```go
|
|
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.
|