Auth & API keys
Email-OTP provisioning, API key scopes (brain:read, brain:write, brain:admin, brain:act-as), key lifecycle, and per-user actor delegation.
Every request carries Authorization: Bearer <token> where the token is an API key with the prefix usk_. Only the provisioning endpoints are unauthenticated. The server is the only security boundary — clients never pre-check scopes.
Get a key (interactive)
unison auth login
# enter your email — new accounts get a key immediately (usage-capped)
# an OTP arrives by email and lifts the caps on verifyRaw HTTP:
# Provision a new account
curl -X POST https://brain.unisonlabs.ai/v1/auth/provision \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com" }'
# Verify OTP (lifts caps on new accounts; mints a new key on existing ones)
curl -X POST https://brain.unisonlabs.ai/v1/auth/verify \
-H "Content-Type: application/json" \
-d '{ "email": "you@example.com", "code": "123456" }'Get a key (CI / machines)
export UNISON_TOKEN=usk_live_… # set from a secret manager
# mint a dedicated key
unison auth keys create --name ci-deploy --scopes brain:read,brain:writeScopes
| Scope | Unlocks |
|---|---|
brain:read | all GETs, key listing, invitations |
brain:write | document write/delete/share, entity upsert, fact record/correct/invalidate, link |
brain:admin | dedup review (merge/unmerge), job retry |
brain:act-as | actor delegation for per-end-user isolation |
A token missing the required scope gets 403 forbidden. New keys can only carry a subset of the minting caller's scopes.
Key lifecycle
# List keys (never returns hashes)
curl 'https://brain.unisonlabs.ai/v1/auth/keys' \
-H "Authorization: Bearer $UNISON_TOKEN"
# Create
curl -X POST https://brain.unisonlabs.ai/v1/auth/keys \
-H "Authorization: Bearer $UNISON_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "ci-deploy", "scopes": ["brain:read", "brain:write"] }'
# token is returned once — store it immediately
# Revoke
curl -X DELETE 'https://brain.unisonlabs.ai/v1/auth/keys/<id>' \
-H "Authorization: Bearer $UNISON_TOKEN"Actor delegation (per-end-user isolation)
One service key can serve many end users. Each X-Unison-Actor id gets an automatically isolated /private/ namespace — no separate account needed per user:
import { BrainClient } from "@unisonlabs/sdk";
const service = new BrainClient({ token: process.env.UNISON_TOKEN });
const u1 = service.withActor("user-001");
await u1.write({ path: "/private/notes/chat.md", bodyMd: "user said …" });
const u2 = service.withActor("user-002");
await u2.search("what did I say?"); // isolated — no cross-actor leakageThe service key must carry brain:act-as. Shadow users are auto-created; each actor shares your workspace's /workspace/ namespace but has an isolated /private/. CLI: --actor <id> or UNISON_ACTOR=<id>.
Inspect the current key
curl 'https://brain.unisonlabs.ai/v1/auth/whoami' \
-H "Authorization: Bearer $UNISON_TOKEN"
# returns: identity, workspaceId, scopes, actedAs (when delegation is active)See also: Scopes & visibility · API reference
Workspaces & teams
A workspace is the top-level isolation boundary. Teams are named sub-groups within it with their own path namespace. Invite members with POST /v1/auth/invitations.
What is a team brain?
A team brain is a shared, persistent knowledge graph that every AI agent and human on a project reads and writes - so no session starts from scratch.