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§
- Tenant
Config - Per-tenant static configuration.
- Tenant
Guard - Requires a resolved tenant AND cross-checks it against the JWT.
- Tenant
Id - Interned tenant identifier (no heap allocation for IDs ≤ 23 bytes).
- Tenant
Registry - Tenant registry with dynamic provisioning.
Enums§
- Tenant
Strategy - How the tenant identifier is carried on the wire.
Statics§
- TENANT
- Ready-to-use singleton.