Skip to main content

Tenants

A tenant is the top-level isolation boundary — above "application," above "user." Every event, policy, app credential, and admin action belongs to exactly one tenant, and every store query, realtime channel, and policy decision is scoped to it.

Tenant isolation is an access rule, not a convention

tenant_id is always derived from the authenticated principal, server-side, at request time — never accepted from a request body, path, or query parameter (the one exception is the tenant-registry resource itself; see below). Concretely: core/tenant.Resolver.Resolve takes a minimal Principal interface (TenantHint() string) and returns a Tenant{ID}, which every handler reads from request context (tenant.FromContext) instead of trusting client input. A buggy filter cannot leak across tenants, because there is no code path where a tenant id originates from the client at all.

Phase 1: one profile, one tenant per process

Today, one running cns-server process serves one tenant, configured via CNS_DEFAULT_TENANT_ID (default katyayani in the shipped default — set your own). tenant.Resolver rejects any token asserting a different tenant. Going multi-tenant later means keying the same Profile struct per tenant_id instead of running one profile globally — not a rewrite. See Advanced & Roadmap.

The tenant registry

Tenants themselves are managed through the Admin API, and are the one admin resource not scoped to the caller's own tenant (the resource is a tenant record) — restricted to the platform-operator role:

MethodPathNotes
GET/admin/v1/tenantsList all tenants.
POST/admin/v1/tenants{id, name}201.
GET/admin/v1/tenants/{id}200 / 404.
PATCH/admin/v1/tenants/{id}{name?, status?}.
DELETE/admin/v1/tenants/{id}204. Does not cascade-delete the tenant's apps/policies/catalog/RBAC grants (Phase-1 gap — no transactional store yet).

Full shapes: API Reference → Admin API.

The four principal types

Every request authenticates as exactly one of these (spec's roles/access model):

PrincipalIdentityScope
Platform operatorAmphoze operator credentialCross-tenant: onboarding, adapter profiles, platform ops — never tenant employee PII
Tenant adminTenant-scoped admin credentialOwn tenant only: apps, policies, analytics
App / publisherService credential (S2S)emit for its own {tenant, app}
Employee / subscriberTenant IdP JWT → subject_idsubscribe/read own subject + authorized groups only

See Authz planes for how these map to the publish, subscribe, and admin authorization decisions, and Apps & credentials / Authentication for how each principal proves who it is.