Identity by key
How API keys carry tenancy in Brain — a key is bound to a (namespace, agent, permissions) scope at creation, and the server derives every request's scope from it.
This is the identity wedge: identity by key. Competing memory APIs ask the caller to send tenancy (user, agent, namespace) on every request, which puts correctness on every line of integration code. Brain flips that — the moment a key is minted it records which namespace (the company / tenant) and which agent (the app) it operates on, and the server refuses to honour any field that disagrees. Every memory, entity, statement, and index is isolated per (namespace, agent); no key can reach another tenant's data.
The practical effect: a client is constructed with just a key. encode, recall, and forget take no scope. The request to the edge carries a body and an auth header, and nothing else identifying the tenant.
import { BrainHttpClient } from "@brain-db/sdk";
const brain = new BrainHttpClient({
apiKey: process.env.BRAIN_API_KEY!,
baseUrl: "https://api.arc-labs.ai",
});
// no namespace, no agent, no scope — the key carries all threeHow the server derives scope
Authentication runs before any handler. It parses the credential, looks up the bound key, constructs the caller's (namespace, agent, permissions) scope, and injects it into the request — handlers read the scope from there, never from the request body.
You can introspect the bound identity any time with whoami (GET /v1/whoami), which returns the resolved namespace, agent, and permissions. Clients cache it per instance, so calling it repeatedly is free.
Authentication
Brain accepts a key on either of two headers — pick one:
Authorization: Bearer <key>X-API-Key: <key>There is nothing else to configure. There is no namespace header and no agent header — sending tenancy alongside a scoped key is not a supported input, because the key already fixes it. Over the wire protocol, auth is sent after the WELCOME handshake as a token (or mTLS); clients then call GET_CAPABILITIES to introspect which capabilities are live on the connected shard. Bad credentials return an authentication error; a key without the right permission bit returns an authorization error before the handler runs. See API: authentication and API: errors.
Permissions
The bound-permissions set gates encode / recall / admin capabilities at the auth layer, before the handler runs. A key minted without the recall capability calling recall is rejected without touching the read pipeline. Permissions are fixed at key creation — to change them, mint a new key with the desired scope and rotate.
Namespace = company, agent = app
The two identity axes are deliberately coarse:
- Namespace is the tenant boundary — a company or customer. It owns memories, entities, the typed graph, and its schema declarations. You create a namespace per product or per customer tier, not per end-user.
- Agent is the application acting inside a namespace. Two agents in one namespace are isolated from each other: one agent's recall never sees the other's memories.
Every row, index, and resolver lookup is keyed under (namespace, agent). See Namespaces for when to draw a new boundary.
Acting on behalf of a tenant — act_as
A trusted service principal (a gateway, a backend serving many tenants from one connection) can run an operation on behalf of a tenant agent by carrying an act_as field. When it's set, the effective identity — the (namespace, agent) named in act_as — is what scopes everything: shard routing, the idempotency key, and the isolation boundary for both reads and writes. A recall under act_as returns the effective identity's memories only, never the service principal's own and never another tenant's.
Why the effective identity keys idempotency
Keying idempotency (and routing) on the effective (namespace, agent) + RequestId is a safety rule, not an optimization. One service principal issuing ops for many tenants over a shared connection could otherwise reuse a RequestId across tenants and have a bare-RequestId key collide — serving one tenant's cached ack to another. Scoping the key by the effective identity makes that collision impossible.
Multi-tenant patterns
One key per tenant app. Mint a key bound to a customer's (namespace, agent) and let that customer's traffic flow through it. Cleanest isolation; you manage a key per tenant and rotate them.
One gateway key + act_as. For a backend serving many tenants from one process, hold a trusted service key and set act_as per request to pin the effective identity. Routing, idempotency, and isolation all follow the effective identity. This is the right pattern when one process fronts many tenants.
What you should never do is share one key across tenants with no act_as — provenance and isolation collapse to a single principal and you lose the ability to reason about one tenant's data in isolation.
Was this page helpful?
Memory types
The five typed-graph kinds Brain extracts — fact, preference, event, entity, relation — and how each is derived, stored, and mutated.
Namespaces
A namespace is Brain's tenant boundary — it owns memories, the entity graph, and schema declarations. It is not a folder. Read this before you create one.