Skip to content

Agent access and scoped tokens

View as Markdown

An agent access token represents one user in one workspace. That association selects identity and row authority; it is not an independently configurable OAuth-style list of action scopes.

On every request, project auth reloads the token’s current user/workspace membership and builds abilities from its current roles. Removing the membership or changing its roles therefore changes later requests. The browser session’s active workspace is irrelevant to a bearer token.

sapporta endpoints list and sapporta endpoints show read the application contract at /api/openapi.json. The generated .env.development sets SAPPORTA_OPENAPI_POLICY=public, so both work against a local development server with no credential, and their output carries each route’s parameters, request body, and response schemas.

The commands that read or write workspace data need a token in SAPPORTA_API_TOKEN: rows, tables, sql, and api. A deployment leaves SAPPORTA_OPENAPI_POLICY unset, which keeps the contract behind sign-in, so endpoint discovery there needs a token as well.

Only a signed-in person creates a token. A freshly scaffolded project has no user until someone signs up, and the data commands are unavailable until then.

Create the token in the intended workspace

Section titled “Create the token in the intended workspace”

An agent access token carries one user and workspace boundary into the CLI, so the setup begins in the browser rather than the terminal. Open /account/profile in an interactive browser session, switch to the workspace the caller should represent, and create an agent access token. Give it a name that identifies the caller and purpose, and add an expiry when the access is temporary.

After creation, the dialog offers two ways to finish. If a coding agent will work from this checkout, open the agent at the project root and choose Copy setup prompt. The prompt already contains the application’s CLI base URL and the one-time token, so paste it into that trusted agent before closing the dialog. If you prefer to configure the environment yourself, choose Copy token and use the manual variables below. Neither route is automatic, and the plaintext token is not available again after the dialog closes.

Later token-list requests return metadata such as the token’s name, workspace, creation time, expiry, last use, and revocation time. The project database stores a hash of the secret rather than the raw token.

The read, create, and delete abilities on agent_access_token authorize these interactive token-management actions. Bearer credentials may call ordinary app APIs, but token-management endpoints reject them with 403 forbidden.

Hand the setup prompt to one trusted agent

Section titled “Hand the setup prompt to one trusted agent”

The setup prompt asks the agent to verify the Sapporta skill and project-local CLI, then reuse the project’s existing directory environment tooling, such as mise, direnv, or a dotenv runner, to provide SAPPORTA_API_URL and SAPPORTA_API_TOKEN to every Sapporta command. If the project has no such tool, the fallback is a private, gitignored local wrapper rather than a newly installed environment manager.

From there, the agent records the exact authenticated invocation in AGENTS.md and proves the connection with a read-only command. In a sandboxed agent, that final check may require explicit network permission for the application URL.

Against a local development server, endpoints list succeeds without a credential and therefore reports reachability rather than the token. Read the auth context to confirm the token itself:

Terminal window
pnpm exec sapporta api get '/api/auth-context'

The generated setup prompt contains the raw credential by design, so treat the whole prompt as a secret-bearing handoff. Paste it only into the intended agent session. The resulting AGENTS.md instruction may name an environment tool or wrapper, but it must never contain the token itself. Keep the credential out of source files, committed configuration, screenshots, shell history, and later task prompts.

The CLI reads SAPPORTA_API_URL and SAPPORTA_API_TOKEN. The URL is the deployment base before /api. The generated prompt includes the base URL derived from the running application; the agent then places it in the project’s private environment tooling. A local development server needs no URL, because the CLI reads the project’s own SAPPORTA_API_PORT from .env.development.

Terminal window
export SAPPORTA_API_URL="https://tasks.example.com"
read -s SAPPORTA_API_TOKEN
export SAPPORTA_API_TOKEN
pnpm exec sapporta endpoints show "GET /api/reports/project-progress"
pnpm exec sapporta rows list tasks --output json

If you call HTTP directly instead, send a normal bearer header:

GET /api/tables/tasks HTTP/1.1
Host: tasks.example.com
Authorization: Bearer spat_<token-id>_<secret>

The token-bound workspace supplies request authority. A query parameter, request body, or workspace_id field cannot switch or widen it.

Protected apps require credentials to retrieve their OpenAPI/endpoint inventory. The inventory proves which operation is mounted and describes its HTTP shape; it does not encode application abilities or row policy.

Choose the narrowest mounted operation that owns the change, make the request, and then read the affected record through an authoritative scoped operation. A successful transport response alone does not prove that the intended row changed.

Use a small fixture with one record in Workspace A and a different record in Workspace B. A Workspace A token should see only Workspace A rows. Automation for Workspace B gets a separate token created while Workspace B is active.

Then exercise each recovery branch:

ConditionStable responseNext step
Revoked token401 token_revokedReplace or remove the credential
Expired token401 token_expiredCreate a new time-bounded token
Membership removed403 workspace_requiredRestore membership or choose another workspace
Bearer calls token-management route403 forbiddenUse an interactive session
Revoke target belongs to another workspace/user404 not_foundRecheck the active browser workspace and token ID

Status and code are the contract. Message wording is illustrative.

Revoking the credential invalidates the next API request. Removing a local environment variable does not revoke it:

Terminal window
unset SAPPORTA_API_TOKEN