auth

package module
v1.7.1 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: AGPL-3.0 Imports: 2 Imported by: 0

README

einherjar/auth

version license go

Not every warrior who knocks at the gate deserves to pass. The Valkyries choose.

Provider-agnostic HTTP authentication and authorization middleware for the Einherjar framework.

Sub-packages

Package Description
authmw HTTP middleware: EnrichmentMiddleware, AuthzMiddleware, SetTokenData, BagEnricher
rbac Permission providers: ClaimsPermissionProvider, CachedPermissionProvider, ChainPermissionProvider

Dependency graph

contracts/security ──► auth/authmw ──► auth/rbac
contracts/security ──► auth/rbac
core/xerrors       ──► auth/authmw
web/httputil       ──► auth/authmw

No external dependencies.

Wiring example

import (
    "code.nochebuena.dev/einherjar/auth/authmw"
    "code.nochebuena.dev/einherjar/auth/rbac"
    "code.nochebuena.dev/einherjar/contracts/security"
)

// Application implements IdentityEnricher to load user data.
enricher := userservice.NewIdentityEnricher(userRepo)

// Build permission resolution chain.
permissions := rbac.NewChainPermissionProvider(
    rbac.NewClaimsPermissionProvider("perms", authmw.GetClaims),               // JWT fast-path
    rbac.NewCachedPermissionProvider(dbProvider, valkeyCache, 5*time.Minute), // DB fallback
)

// Provider AuthMiddleware (from auth-jwt or auth-firebase) goes first.
// Then enrichment globally:
srv.Use(authmw.EnrichmentMiddleware(logger, enricher,
    authmw.WithTenantHeader("X-Tenant-ID"),
))

// Per-route authorization:
const ReadOrders = security.Permission(0)
srv.With(authmw.AuthzMiddleware(logger, permissions, "orders", ReadOrders)).
    Get("/orders", ordersHandler)

Custom enrichment

BagEnricher lets you attach any request attribute to the SecurityBag in context. Permission providers read it via bag.Get(key) — no scattered context keys.

const KeyHardwareID = "hardware_id"  // owned by your package; document the value type

hwEnricher := authmw.BagEnricher(func(bag security.SecurityBag, r *http.Request) security.SecurityBag {
    return bag.With(KeyHardwareID, r.Header.Get("X-Hardware-ID"))
})

srv.Use(authmw.EnrichmentMiddleware(logger, enricher,
    authmw.WithTenantHeader("X-Tenant-ID"),
    authmw.WithBagEnricher(hwEnricher),
))

With a hardware-ID-bound permission model, override the cache key so the hardware ID is included — otherwise two hardware IDs for the same user share a cache entry:

cached := rbac.NewCachedPermissionProvider(dbProvider, cache, 5*time.Minute,
    rbac.WithCacheKey(func(bag security.SecurityBag, uid, resource string) string {
        hwID, _ := bag.Get(KeyHardwareID)
        return fmt.Sprintf("rbac:%s:%s:%v:%s", bag.Identity().TenantID, uid, hwID, resource)
    }),
)

Multi-tenant

// Read TenantID from header; CachedPermissionProvider scopes keys automatically.
srv.Use(authmw.EnrichmentMiddleware(logger, enricher, authmw.WithTenantHeader("X-Tenant-ID")))
  • JWT carries "who are you" only — no per-tenant permission claims required
  • WithTenantHeader populates security.Identity.TenantID from the request
  • CachedPermissionProvider uses "rbac:{tenantID}:{uid}:{resource}" when TenantID is non-empty

Permission model

Permissions are a 63-bit set (security.Permission(0) through security.MaxPermission). Define application permissions as constants:

const (
    Read   = security.Permission(0)
    Write  = security.Permission(1)
    Delete = security.Permission(2)
    Admin  = security.Permission(3)
)

Issue tokens with embedded masks (via auth-jwt):

customClaims := map[string]any{
    "perms": map[string]any{
        "orders": int64(security.PermissionMask(0).Grant(Read).Grant(Write)),
    },
}

Environment variables

None. Auth middleware is wired in code, not configured via environment.

Install

go get code.nochebuena.dev/einherjar/auth@v1.1.2

Documentation

Overview

Package auth provides provider-agnostic HTTP authentication and authorization middleware for the Einherjar framework.

auth absorbs two micro-lib packages:

  • httpauth → sub-package authmw (middleware + identity enrichment)
  • rbac → sub-package rbac (permission provider implementations)

Types that cross the full dependency graph (Identity, Permission, PermissionMask, PermissionProvider) live in contracts/security, not here. This module provides implementations and middleware, not type definitions.

Sub-packages

[authmw] — HTTP middleware layer. Three functions compose the full auth chain:

  • [authmw.SetTokenData] — integration contract called by provider packages (auth-jwt, auth-firebase) after token verification.
  • [authmw.EnrichmentMiddleware] — converts uid+claims into a security.Identity and stores it in context. The application provides the [authmw.IdentityEnricher] implementation that loads user data.
  • [authmw.AuthzMiddleware] — per-route permission gate. Takes a [security.PermissionProvider] and the required permission for the route.

[rbac] — permission resolution. Three provider implementations satisfy [security.PermissionProvider]:

  • [rbac.NewClaimsPermissionProvider] — reads pre-computed bitmasks from JWT claims. Zero DB calls. Single-tenant fast-path.
  • [rbac.NewCachedPermissionProvider] — wraps any provider with a TTL cache. Cache keys are automatically scoped by TenantID when present.
  • [rbac.NewChainPermissionProvider] — tries providers in order; returns the first non-zero mask. Typical: claims fast-path → cached DB fallback.

Wiring Example

enricher := userservice.NewIdentityEnricher(userRepo)

permissions := rbac.NewChainPermissionProvider(
    rbac.NewClaimsPermissionProvider("perms", authmw.GetClaims),
    rbac.NewCachedPermissionProvider(dbProvider, valkeyCache, 5*time.Minute),
)

// After provider AuthMiddleware (from auth-jwt or auth-firebase):
srv.Use(authmw.EnrichmentMiddleware(logger, enricher))

// Per-route authorization:
srv.With(authmw.AuthzMiddleware(logger, permissions, "orders", security.Permission(0))).
    Get("/orders", ordersHandler)

Multi-tenant

Pass the tenant identifier via a request header:

srv.Use(authmw.EnrichmentMiddleware(logger, enricher, authmw.WithTenantHeader("X-Tenant-ID")))

[authmw.WithTenantHeader] populates [security.Identity.TenantID] from the header. [rbac.NewCachedPermissionProvider] automatically scopes its cache keys by TenantID when non-empty — no additional configuration required.

Index

Constants

This section is empty.

Variables

View Source
var Module observability.Identifiable = &moduleID{}

Module identifies this package to observability systems. auth is middleware-only — it is not registered with the launcher as a lifecycle component. Register Module manually with any version registry if needed.

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
Package authmw provides provider-agnostic HTTP authentication and authorization middleware for the Einherjar framework.
Package authmw provides provider-agnostic HTTP authentication and authorization middleware for the Einherjar framework.
Package rbac provides permission provider implementations for the Einherjar authorization system.
Package rbac provides permission provider implementations for the Einherjar authorization system.

Jump to

Keyboard shortcuts

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