Docs navigation
Reference

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.

AxisValuesWhat it decides
Permission scoperead, publish, adminWhether the token may write. Chosen at mint time with --scopes.
Resource scopeuser-wide, or one agent / threadWhether 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.

bash
brainbase token create --name ci                       # scopes: read, publish
brainbase token create --name ci-readonly --scopes read
brainbase token list                                   # scopes per token
ScopeWhat it grants
readEvery read endpoint. Grants no writes. Most reads do not check for it; the three surface-settings reads on /v2/cli do — see below.
publishEvery write endpoint. On its own it does not pass the three surface reads that require read.
adminNothing. Accepted at mint time; no endpoint requires it.
The admin scope grants nothing today
No endpoint requires 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.

ScopeRequired by
code:executePOST /v2/tasks/{task_id}/code/run/sync and GET /v2/tasks/{task_id}/code/capabilities, in addition to publish.
messages:write_rolesAppending 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.

Defaults differ between the CLI and the raw API
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.

EndpointScope required
POST /v2/cli/orgs/{org_id}/teamspublish
POST /v2/cli/agentspublish
PUT /v2/cli/agents/{agent_id}publish
PUT /v2/cli/agents/{agent_id}/manifestpublish
PUT /v2/cli/agents/{agent_id}/secretspublish
POST /v2/cli/agents/{agent_id}/keyspublish
DELETE /v2/cli/keys/{key_id}publish
PUT /v2/cli/agents/{agent_id}/connections/slackpublish
DELETE /v2/cli/agents/{agent_id}/connections/slackpublish
PUT /v2/cli/agents/{agent_id}/connections/meetingpublish
DELETE /v2/cli/agents/{agent_id}/connections/meetingpublish
POST /v2/cli/agents/{agent_id}/mcp-connect-linkspublish
PUT /v2/cli/agents/{agent_id}/surfaces/slackpublish
PUT /v2/cli/agents/{agent_id}/surfaces/meetingpublish
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/calendarpublish
PATCH /v2/cli/agents/{agent_id}/surfaces/meeting/calendarpublish
POST /v2/cli/agents/{agent_id}/surfaces/meeting/imagepublish
POST /v2/cli/agents/{agent_id}/surfaces/phone/whitelistpublish
DELETE /v2/cli/agents/{agent_id}/surfaces/phone/whitelist/{entry_id}publish
POST /v2/cli/orchestrationspublish
PUT /v2/cli/orchestrations/{orch_id}publish
GET /v2/cli/agents/{agent_id}/surfaces/{surface}read
GET /v2/cli/agents/{agent_id}/surfaces/meeting/calendarread
GET /v2/cli/agents/{agent_id}/surfaces/phone/whitelistread
Every other GET under /v2/clinone

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.

A read-scoped PAT is not read-only across the whole product
On /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:

json
{
  "detail": "PAT lacks required scope: publish"
}

Two nearby failures that are not scope failures, and have different fixes:

ResponseMeaning
401 missing bearer tokenNo Authorization header.
401 invalid or expired PATThe token does not resolve — revoked, expired, or mistyped.
403 credential_scope_deniedThe 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 configurationAn 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.

BindingMinted byReaches
User-widebrainbase token create, or the dashboardEverything the user can reach.
One agentBrainbase, when an agent's sandbox starts or a scheduled trigger firesThat agent, plus orchestration peers it has an edge to.
One threadBrainbase, per running threadThat thread.
Most of that boundary is still in shadow mode
The general guards are deployed but not enforcing: they are gated on a server setting that defaults to logging a would-be denial and allowing the request through. A few places on /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, rename and revoke reject a PAT with jwt_required. token list accepts 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 integrations and the provider operations of agent surface — GitHub and Linear setup, the Linear manifest and disconnect, and phone search, purchase and release — refuse while BRAINBASE_TOKEN is set.
  • Saved PATs are a fallback for every authenticated command. BRAINBASE_TOKEN takes priority, then a valid or renewable login session, then a usable saved PAT. See Authentication.