Tenant Isolation
Hard multi-tenancy with per-tenant policy namespaces and audit streams.
Tenant Isolation
CoreSDK provides hard tenant isolation at the policy, audit log, and rate-limit layers.
How isolation works
Every request carries a tenant_id — extracted from the JWT claim tenant_id. CoreSDK scopes all policy evaluations, audit writes, and trace attributes to that tenant.
Tenant resolution
The tenant_id is always read from the verified JWT claim. It is never trusted from a query parameter or arbitrary header.
use coresdk_engine::Engine;
// Engine reads CORESDK_* env vars; tenant_id comes from JWT claim
let engine = Engine::from_env().await?;from coresdk import CoreSDKClient, SDKConfig
from fastapi import Request
_sdk = CoreSDKClient(SDKConfig(
sidecar_addr="[::1]:50051",
tenant_id="acme-corp",
fail_mode="open",
))
# Tenant comes from JWT claim tenant_id — always from token, never query param
def get_tenant(request: Request) -> str:
user = getattr(request.state, "coresdk_user", None) or {}
return user.get("tenant_id") or "default"
# Scope all DB queries by tenant
@app.get("/products")
async def list_products(request: Request):
tenant = get_tenant(request)
return db.products.for_tenant(tenant)// Go SDK ships Phase 2
// tenant_id is resolved from the verified JWT claim automatically// TypeScript SDK ships Phase 2
// tenant_id is resolved from the verified JWT claim automaticallyPolicy namespaces
Each tenant can have its own policy file that overrides the global policy:
policies/
global.rego # applies to all tenants
tenants/
acme.rego # overrides for tenant "acme"
beta-corp.rego # overrides for tenant "beta-corp"# policies/tenants/acme.rego
package coresdk.authz
# Acme gets extra analytics access
allow {
input.action == "analytics:read"
input.user.tenant_id == "acme"
}Per-tenant rate limits
Phase 2. Per-tenant rate limit configuration ships Phase 2. Phase 1 enforces a single global rate limit via the sidecar.
Configure per-tenant limits in coresdk.toml:
[sdk]
sidecar_addr = "[::1]:50051"
tenant_id = "acme-corp"
service_name = "my-api"
fail_mode = "open"
[[tenants]]
acme-corp = { display_name = "Acme Corp" }
globex = { display_name = "Globex" }Tenant provisioning API
Phase 2. The programmatic tenant provisioning API ships Phase 2. In Phase 1, tenants are declared in
coresdk.tomlunder[[tenants]].
Cross-tenant access
Phase 2. Cross-tenant service tokens ship Phase 2.
Cross-tenant access is always logged separately in the audit stream.
Audit stream per tenant
Phase 2. Per-tenant audit stream export (S3, GCS, HTTP) ships Phase 2. Phase 1 writes audit events to the local OTel pipeline.