PAT scopes
A personal access token (bbpat_…) carries a list of permission scopes, fixed when the token is minted. This page states exactly which scopes exist, what each one grants today, and which endpoints check them.
Two independent axes
Two separate things are called "scope" in the product, and they are checked independently. A request has to satisfy both.
| Axis | Values | What it decides |
|---|---|---|
| Permission scope | read, publish, admin | Whether the token may write. Chosen at mint time with --scopes. |
| Resource scope | user-wide, or one agent / thread | Whether the token acts for the whole user or for a single resource. Not selectable from the CLI. |
Every PAT from brainbase token create is user-wide. Resource-scoped PATs exist, but only Brainbase mints them — see Resource scope.
Permission scopes
brainbase token create accepts a comma-separated list. Three values are allowed; anything else is rejected locally before the request is sent, and again by the server.
brainbase token create --name ci # scopes: read, publish
brainbase token create --name ci-readonly --scopes read
brainbase token list # scopes per token
| Scope | What it grants |
|---|---|
read | Every read endpoint. Grants no writes. Most reads do not check for it; the three surface-settings reads on /v2/cli do — see below. |
publish | Every write endpoint. On its own it does not pass the three surface reads that require read. |
admin | Nothing. Accepted at mint time; no endpoint requires it. |
admin. A token minted with --scopes admin and nothing else is refused on writes with the same "lacks required scope: publish" error a read-only token gets, and on the surface reads with "lacks required scope: read". If you want a token that can write, include publish; keep read alongside it, as the default read,publish does.Two further scopes exist in the platform and are enforced, but you cannot mint them: the token endpoint rejects anything outside read, publish and admin. They are issued internally to the credentials Brainbase plants in a sandbox, listed here so an unfamiliar scope name in an error is identifiable.
| Scope | Required by |
|---|---|
code:execute | POST /v2/tasks/{task_id}/code/run/sync and GET /v2/tasks/{task_id}/code/capabilities, in addition to publish. |
messages:write_roles | Appending a message whose role is not user, when the caller is a resource-scoped PAT rather than an agent manager. |
Scopes are immutable. token rename changes only the label; to change what a token can do, mint a replacement and revoke the old one.
brainbase token create with no --scopes sends read,publish. The underlying mint endpoint defaults to read alone when the field is omitted, so a token created outside the CLI may be read-only even though the CLI's default is not.What is actually enforced
On the CLI control plane at /v2/cli, every write requires the publish scope: all 23 mutating endpoints carry the check. Of the 20 read endpoints, 17 require no scope and three — the surface-settings reads behind agent surface — require read.
| Endpoint | Scope required |
|---|---|
POST /v2/cli/orgs/{org_id}/teams | publish |
POST /v2/cli/agents | publish |
PUT /v2/cli/agents/{agent_id} | publish |
PUT /v2/cli/agents/{agent_id}/manifest | publish |
PUT /v2/cli/agents/{agent_id}/secrets | publish |
POST /v2/cli/agents/{agent_id}/keys | publish |
DELETE /v2/cli/keys/{key_id} | publish |
PUT /v2/cli/agents/{agent_id}/connections/slack | publish |
DELETE /v2/cli/agents/{agent_id}/connections/slack | publish |
PUT /v2/cli/agents/{agent_id}/connections/meeting | publish |
DELETE /v2/cli/agents/{agent_id}/connections/meeting | publish |
POST /v2/cli/agents/{agent_id}/mcp-connect-links | publish |
PUT /v2/cli/agents/{agent_id}/surfaces/slack | publish |
PUT /v2/cli/agents/{agent_id}/surfaces/meeting | publish |
PATCH /v2/cli/agents/{agent_id}/surfaces/{surface} | publish |
DELETE /v2/cli/agents/{agent_id}/surfaces/{surface} | publish |
POST /v2/cli/agents/{agent_id}/surfaces/meeting/calendar | publish |
PATCH /v2/cli/agents/{agent_id}/surfaces/meeting/calendar | publish |
POST /v2/cli/agents/{agent_id}/surfaces/meeting/image | publish |
POST /v2/cli/agents/{agent_id}/surfaces/phone/whitelist | publish |
DELETE /v2/cli/agents/{agent_id}/surfaces/phone/whitelist/{entry_id} | publish |
POST /v2/cli/orchestrations | publish |
PUT /v2/cli/orchestrations/{orch_id} | publish |
GET /v2/cli/agents/{agent_id}/surfaces/{surface} | read |
GET /v2/cli/agents/{agent_id}/surfaces/meeting/calendar | read |
GET /v2/cli/agents/{agent_id}/surfaces/phone/whitelist | read |
Every other GET under /v2/cli | none |
The same check refuses an agent task key (bb_live_…) outright on every endpoint in the table above that names a scope, with CLI task keys cannot manage cloud configuration.
Outside /v2/cli the rule is patchier. Some writes check publish unconditionally: agent secrets, file uploads, thread creation, orchestration writes, and the benchmark mutations. Others are covered only by a newer blanket guard that is deployed but not yet enforcing — it is gated on a server setting that currently logs a would-be denial and lets the request through. Templates, machines, evals, alerts, orchestration templates and most of PATCH /v2/agents/{agent_id} sit in that group.
/v2/cli it is, with no exceptions. Elsewhere, a read-only PAT can still reach the writes covered only by the non-enforcing guard. Treat read as a guardrail for CLI use, not as a product-wide read-only credential. Reads are gated in only two places: the three surface reads on /v2/cli, which need read, and task code execution, which needs code:execute on both its read and its write.The check applies to PATs only. A browser login session is a Supabase JWT and carries no scope list, so it is never scope-checked and can always write whatever the user's role allows.
Error responses
A token without the scope a write needs gets 403 before the handler runs, so nothing is created or modified:
{
"detail": "PAT lacks required scope: publish"
}
Two nearby failures that are not scope failures, and have different fixes:
| Response | Meaning |
|---|---|
401 missing bearer token | No Authorization header. |
401 invalid or expired PAT | The token does not resolve — revoked, expired, or mistyped. |
403 credential_scope_denied | The token resolved and has the right permission scope, but it is bound to a single resource. Two /v2/cli routes raise this today, listing a team's agents and listing an organization's members — see Resource scope. |
403 CLI task keys cannot manage cloud configuration | An agent task key (bb_live_…) on a write, or on a surface read. Those need a PAT or a session. |
Resource scope
Independently of read/publish/admin, a credential is either user-wide or bound to exactly one resource. The intent is that a resource-bound credential cannot reach routes that configure things above a single resource — orgs, teams, agent creation — even when it carries publish.
| Binding | Minted by | Reaches |
|---|---|---|
| User-wide | brainbase token create, or the dashboard | Everything the user can reach. |
| One agent | Brainbase, when an agent's sandbox starts or a scheduled trigger fires | That agent, plus orchestration peers it has an edge to. |
| One thread | Brainbase, per running thread | That thread. |
/v2/cli refuse unconditionally today: listing a team's agents, listing an organization's members, the five orchestration endpoints, and — for thread-bound credentials — the surface-settings endpoints. Other routes may still admit a resource-scoped credential in shadow mode, but opt-in strict admission refuses them on protected writes, including eval writes. Do not treat resource binding alone as a security boundary you can rely on.With strict admission enabled, alert creation, changes, deletion and signing-secret rotation, plus agent and orchestration template writes, also require a person's session or user-wide PAT under the existing group or team permissions. Resource credentials receive 403 with detail.code: agent_credential_refused before configuration is saved. Task model and metadata updates distinguish execution settings from ordinary label edits. Reads retain their existing permissions. Strict admission is off by default and requires both INTEGRATION_CONTROL_ENABLED=true and cutover:strict_admission=true, independently of tier shadow mode. If the master switch is on but the strict-admission setting cannot be read, protected resource writes return 503 with detail.code: origin_unavailable and Retry-After: 5.
Strict admission also confines runtime-event writes to the credential's own task or a task it delegated to in the same context. A sandbox PAT cannot write another context's transcript just because both tasks use the same agent. Both /internal/events and /v2/internal/events apply this rule before saving events or starting terminal-event work. Existing exact task-key scope and human/service authorization still apply. Cross-context or ambiguous task identifiers return 403 with detail.code: cross_context; writes from a child into its parent return detail.code: not_descendant. Strict-off behavior is unchanged.
The refusals read differently. GET /orgs/{org_id}/teams/{team_id}/agents and GET /orgs/{org_id}/members answer with the credential_scope_denied object listed above. The orchestration endpoints answer with a plain string naming the binding, for example agent-scoped PATs cannot access orchestration configuration. The surface endpoints accept a user-wide or agent-bound credential and refuse anything narrower with Surface settings require a user or agent credential.
You cannot mint a resource-scoped PAT from the CLI, and you do not need to: the resource-scoped tokens an agent uses are planted in its sandbox automatically. The distinction matters when reading an error — a 403 naming credential_scope_denied came from a token Brainbase minted for a sandbox, not from a token you created.
Which credential each surface accepts
A PAT and a login session are not interchangeable everywhere. Three rules cover it:
- Minting or changing PATs requires a login session.
token create,renameandrevokereject a PAT withjwt_required.token listaccepts a user-level PAT. - Everything else on the control plane accepts either. A PAT with the right scopes can do anything a session can, subject to the scope rules above.
- Some commands call the web app, not the control plane, and need a session.
brainbase integrationsand the provider operations ofagent surface— GitHub and Linear setup, the Linear manifest and disconnect, and phone search, purchase and release — refuse whileBRAINBASE_TOKENis set. - Saved PATs are a fallback for every authenticated command.
BRAINBASE_TOKENtakes priority, then a valid or renewable login session, then a usable saved PAT. See Authentication.