Architecture · Multi-tenant
Multi-tenant isolation
How Cognitive Server enforces hard tenant boundaries across every layer of the stack — from the JWT to the vector store.
JWT & Tenant-ID
Every request to Cognitive Server carries a JWT issued and signed by Shield. The token payload contains three mandatory claims:
- tenant_id (UUID v7): the unique identifier of the operating tenant. Every component downstream uses this claim to scope reads and writes.
- scope[]: the exact set of permissions active for this request. No implicit scopes exist; if a scope is absent from the token, the corresponding resource or action is unavailable.
- jti (JWT ID): a unique token identifier used for anti-replay validation. Shield rejects any
jtiit has already seen within the token's lifetime.
{
"iss": "https://shield.cognitive.local",
"sub": "operator_01J8...",
"tenant_id": "acme-bank_01J8...",
"scope": ["vault:read", "audit:export", "skill:execute:approved"],
"jti": "tok_01J8...",
"iat": 1751000000,
"exp": 1751003600
}The tenant_id propagates through the entire call chain — Core → Nexus → Vault → Hub. No component accepts a request without a valid tenant_id in the JWT. Cross-tenant reads are structurally impossible: the query layer always injects the tenant_id as a mandatory filter before executing.
tenant_id. There is no super-tenant or admin bypass mode. Even administrative operations require a tenant-scoped token with the admin scope explicitly granted.Isolation contract
Tenant isolation is physical and logical simultaneously. The following constraints are enforced at the data layer, not at the application layer:
- Vector namespace isolation: each tenant's embeddings live in a dedicated Qdrant collection prefixed by
tenant_id. Cross-namespace queries return 403 before touching storage. - Row-level security (PostgreSQL): every table carries a
tenant_idcolumn. Shield-issued RLS policies activate on connection and make cross-tenant rows invisible — they do not appear in query plans. - Chain ledger partitioning: trace events are written to tenant-partitioned append logs. Regulators receive an export scoped to their tenant; the export API rejects requests without a matching
tenant_id. - Redis keyspace prefixing: all cache keys are prefixed
tenant_id:. A keyspace notification flood from one tenant cannot bleed into another's event stream.
Dynamic Client Registration
Cognitive Server follows the OAuth 2.1 Dynamic Client Registration protocol (RFC 7591) for onboarding new tenants. The flow:
- The operator submits a registration request to Shield's
/registerendpoint, including thetenant_id, the allowed redirect URIs, and the public key for token verification. - Shield issues a
client_idand aclient_secretencrypted with the tenant's public key. The plaintext secret never transits the network. - The operator stores the
client_secretin their HSM or secrets manager. Shield never stores or logs the plaintext. - Token rotation is non-disruptive: the operator initiates rotation via
/registerwith the existingclient_id; Shield issues new credentials before invalidating the old ones.
// Registration request
POST /register
{
"tenant_id": "acme-bank_01J8...",
"redirect_uris": ["https://acme-bank.internal/callback"],
"jwks_uri": "https://acme-bank.internal/.well-known/jwks.json",
"token_endpoint_auth_method": "private_key_jwt"
}
// Shield response
{
"client_id": "client_01J8...",
"client_id_issued_at": 1751000000,
"client_secret_expires_at": 0
}