Skip to main content

Module tenant

Module tenant 

Source
Expand description

Multi-tenant separation layer.

Tenant identity is resolved once per request inside web::boundary::assemble_context — the same single pipeline that handles credentials and tracing — so every entry point (macro routes, plugin routes) sees the same tenant with zero per-handler boilerplate.

§Hot-path guarantees

TenantRegistry is a frozen map built once at boot and provided into the DI container: resolution is a header read + immutable HashMap lookup — no locks, no allocation beyond the interned SmolStr key.

§Defense in depth

A client-supplied header is never trusted on its own. When the request also carries a JWT with a tenant claim, TenantGuard enforces that both agree — a token minted for tenant A can never act on tenant B by forging X-Tenant-Id.

§Usage

// boot (plugin on_init):
ctx.provide(TenantRegistry::new(
    TenantStrategy::Header("x-tenant-id"),
    vec![
        TenantConfig::new("acme",  "Acme Corp", "acme_primary"),
        TenantConfig::new("globex", "Globex",    "globex_primary"),
    ],
    Some(TenantId::new("public")),       // fallback tenant (None = strict)
));

// handler:
static TENANT: TenantGuard = TenantGuard;
TENANT.check(&ctx)?;
let t = ctx.tenant().expect("guarded");

Structs§

TenantConfig
Per-tenant static configuration.
TenantGuard
Requires a resolved tenant AND cross-checks it against the JWT.
TenantId
Interned tenant identifier (no heap allocation for IDs ≤ 23 bytes).
TenantRegistry
Tenant registry with dynamic provisioning.

Enums§

TenantStrategy
How the tenant identifier is carried on the wire.

Statics§

TENANT
Ready-to-use singleton.