Files
auth/CHANGELOG.md

48 lines
2.7 KiB
Markdown
Raw Normal View History

feat(auth): initial implementation — authmw and rbac (v1.0.0) Introduces code.nochebuena.dev/einherjar/auth — the provider-agnostic HTTP authentication and authorization layer of the Einherjar framework. Absorbs two micro-lib packages (httpauth, rbac) as sub-packages, replacing the Identity-only context model with a SecurityBag-native design and adding a composable enrichment chain. authmw: - BagEnricher function type — enriches the request-scoped SecurityBag after the base Identity is built; registered via WithBagEnricher; multiple enrichers run in order, each receiving the bag from the previous - IdentityEnricher interface — application-layer contract for loading user data from uid+claims - EnrichmentMiddleware — builds SecurityBag from uid+claims, runs enricher chain, stores via security.SetBagInContext; 401 on missing uid, 500 on enricher error; routes all errors through httputil.Error - AuthzMiddleware — per-route permission gate; 401 on missing identity, 403 on provider error (fail-closed) or insufficient permissions - EnrichOpt type + WithTenantHeader (reads TenantID from header, implemented as a BagEnricher) + WithBagEnricher (registers custom enrichers for hardware IDs, grant codes, or any bag attribute) - SetTokenData / GetClaims — integration contract for auth-jwt / auth-firebase rbac: - NewClaimsPermissionProvider — reads flat JWT claim bitmasks from context; wildcard "*" fallback; handles int64/float64/json.Number; zero DB calls - NewCachedPermissionProvider — TTL cache wrapping any PermissionProvider; default key "rbac:{uid}:{resource}" or "rbac:{tenantID}:{uid}:{resource}"; TenantID sourced from SecurityBag automatically; accepts ...CachedOpt - CachedOpt type + WithCacheKey — overrides the key function for extra dimensions (hardware IDs, grant codes read from bag attributes) - NewChainPermissionProvider — tries providers in order; first non-zero wins; errors short-circuit; typical pattern: claims → cached DB fallback - Cache interface — pluggable backend satisfied by cache-valkey via duck typing Compliance test (package auth_test) enforces CT-6 (≤1 exported TypeSpec/file), compile-time interface satisfaction, and behavioural coverage across the full middleware and provider surface: enrichment success/failure, tenant header, custom BagEnricher, bag-in-context, authz allowed/denied/error, claims hit/wildcard/missing/float64, cached hit/miss/error/tenant-key/custom-key, chain first-non-zero/fallthrough/error. Depends on contracts v1.0.0, core v1.0.0, web v1.0.0. - identifiable.go: package-level Module variable (observability.Identifiable) for version identification — auth is middleware-only; not registered with the launcher
2026-05-29 16:11:21 +00:00
# Changelog
## v1.0.0
Initial release.
### `authmw`
- `BagEnricher` type — `func(bag security.SecurityBag, r *http.Request) security.SecurityBag`;
enriches the request-scoped SecurityBag after the base Identity is built. Register via
`WithBagEnricher`. Multiple enrichers run in registration order, each receiving the bag
returned by the previous one.
- `SetTokenData` — integration contract for provider packages (auth-jwt, auth-firebase).
Stores uid and raw claims in context via typed keys; consumed by `EnrichmentMiddleware`.
- `GetClaims` — exported accessor for raw token claims stored by `SetTokenData`. Available
to custom `IdentityEnricher` implementations and `ClaimsPermissionProvider`.
- `EnrichmentMiddleware` — builds a `security.SecurityBag` from uid+claims. Calls the
application `IdentityEnricher`, wraps the Identity in a SecurityBag, runs all registered
`BagEnricher` functions in order, then stores the bag via `security.SetBagInContext`.
Accepts `logging.Logger`; routes errors through `httputil.Error` (401 on missing token,
500 on enricher failure).
- `AuthzMiddleware` — per-route permission gate. Returns 401 on missing identity, 403 on
provider error or insufficient permissions (fail-closed).
- `IdentityEnricher` interface — implemented by the application to load user data from uid+claims.
- `EnrichOpt` type — `func(*enrichConfig)`.
- `WithTenantHeader(header string) EnrichOpt` — reads Identity.TenantID from a named request
header. Implemented as a `BagEnricher` internally.
- `WithBagEnricher(fn BagEnricher) EnrichOpt` — registers a custom enricher. Use for any
attribute beyond TenantID: hardware IDs, grant codes, etc.
### `rbac`
- `NewClaimsPermissionProvider` — reads pre-computed bitmasks from JWT claims in context.
Flat format: `claims[claimsKey][resource] = mask`. Wildcard `"*"` fallback.
Handles int64, float64, json.Number.
- `NewCachedPermissionProvider` — wraps any `security.PermissionProvider` with TTL caching.
Default cache key: `"rbac:{uid}:{resource}"` (single-tenant) or
`"rbac:{tenantID}:{uid}:{resource}"` (multi-tenant). TenantID sourced from the SecurityBag
in context automatically. Accepts `...CachedOpt` for customization.
- `CachedOpt` type — `func(*cachedConfig)`.
- `WithCacheKey(fn func(security.SecurityBag, string, string) string) CachedOpt` — overrides
the default cache key function. Use when additional bag attributes (hardware IDs, grant codes)
must be part of the key.
- `NewChainPermissionProvider` — tries providers in order; returns first non-zero mask. Errors
short-circuit.
- `Cache` interface — pluggable cache backend. Satisfied by `einherjar/cache-valkey` via duck
typing.