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. Nothing checks for it — it is simply the absence of publish.
publishEvery write endpoint. Of the three scopes you can mint, this is the only one anything checks.
adminNothing beyond read. 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. If you want a token that can write, include publish.

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, the rule has no exceptions: every write requires the publish scope, and no read requires any scope. All 13 mutating endpoints carry the check; all 15 read endpoints carry none.

EndpointScope required
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/orgs/{org_id}/teamspublish
POST /v2/cli/orchestrationspublish
PUT /v2/cli/orchestrations/{orch_id}publish
Every GET under /v2/clinone

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. The one place a read is gated at all is 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. Only one /v2/cli route raises this today — see Resource scope.

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. Two places on /v2/cli refuse unconditionally today — listing a team's agents, and the five orchestration endpoints. Everything else admits a resource-scoped credential for now, so do not treat resource binding as a security boundary you can rely on.

The two refusals also read differently. GET /orgs/{org_id}/teams/{team_id}/agents answers 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.

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 and managing PATs requires a login session. token create, list, rename and revoke all reject a PAT with jwt_required — a PAT cannot mint another PAT.
  • Everything else on the control plane accepts either. A PAT with the right scopes can do anything a session can, subject to the publish rule above.
  • The PAT has to be in the BRAINBASE_TOKEN environment variable for control-plane commands. A PAT saved on disk by token create is not read by agent, orchestration, link, unlink, sync, status or team. See Authentication.