Scopes

Scope format, built-in endpoint permissions, and custom route policies.

Scopes are permission strings carried by the caller's credential: the JWT scopes claim, or the stored scopes of a service account token. Protected operations with insufficient scopes usually return 403 Forbidden. Agent, team, and workflow listings can instead return a filtered or empty list. Unmapped custom routes have no automatic scope requirement.

Scope Format

Scopes are hierarchical:

FormatExampleDescription
resource:actionagents:readAccess all resources of a type
resource:<id>:actionagents:my-agent:runAccess a specific resource
resource:*:actionagents:*:readWildcard (equivalent to global)
agent_os:admin-Full access to all endpoints

Scope Reference

Scopes are enforced at two layers. Control plane scopes are enforced by the AgentOS control plane at os.agno.com. AgentOS scopes are enforced by your deployed AgentOS service on every API request.

Any agents:action, teams:action, or workflows:action scope also accepts a resource:<id>:action form to limit access to a specific resource. For example, agents:web-agent:run grants run access only to the web-agent. Use * as the id (agents:*:run) to match every resource of that type. See Scope Format.

Per-resource scoping applies to agents, teams, and workflows only. All other resource types (sessions, memories, knowledge, traces, etc.) use global scopes only. The resource:<id>:action form is not honored for them.

The agent_os:admin scope grants full access to every AgentOS endpoint below.

AgentOS Control Plane Scopes

ScopeDescription
os:readView AgentOS instances in the organization
os:writeCreate and update AgentOS instances
os:deleteDelete AgentOS instances
org:readView organization details
org:writeUpdate organization details
org:deleteDelete the organization
org:members:readView organization members
org:members:writeInvite and update organization members
org:roles:readView organization roles and their scope assignments
org:roles:writeCreate and update organization role scopes
org:roles:deleteDelete organization roles
billing:readView billing details and invoices
billing:writeUpdate billing settings and payment methods

AgentOS Scopes

ScopeEndpointDescription
config:readGET /configRead the OS configuration
config:writePOST /databases/all/migrateRun migrations on all databases
config:writePOST /databases/*/migrateRun migrations on a specific database

Legacy system:read and system:write scopes are accepted as aliases for config:read and config:write, so tokens issued before the rename keep working. Use config:read and config:write in new tokens; action wildcards such as config:* are not supported.

Run polling, history, and checkpoint reads require both scopes shown above: middleware checks the resource's read permission and the run handler checks its run permission. Equivalent per-resource grants can target a specific component. A default service-account token has run permissions but lacks agent, team, and workflow read permissions, so add the relevant read grant before polling protected REST run endpoints.

AG-UI's POST /agui route requires a global or wildcard run grant for its target family, such as agents:run or agents:*:run, or the corresponding team grants. A specific-agent or specific-team grant does not pass this route's scope check. Custom AG-UI prefixes use the same family requirement.

Access Prerequisites

A few scopes gate access in the control plane. Without them, finer-grained scopes have no effect because the user cannot reach the resources they apply to.

ScopeWithout it, the user cannot
org:readAccess the organization at all
os:readList AgentOS instances in the organization
config:readLoad AgentOS configuration in the control-plane UI (GET /config on startup)

Direct API calls need the scopes of their own operations; config:read is not a prerequisite for every endpoint.

Custom Scope Mappings

Customize or extend the default scope mappings using the JWT middleware:

from agno.os import AgentOS
from agno.os.middleware import JWTMiddleware

agent_os = AgentOS(
    id="my-agent-os",
    agents=[my_agent],
)

app = agent_os.get_app()

app.add_middleware(
    JWTMiddleware,
    verification_keys=["your-jwt-key"],
    algorithm="RS256",
    authorization=True,
    scope_mappings={
        "POST /custom/endpoint": ["custom:write"],  # custom route: full freedom
        "GET /custom/data": ["custom:read"],        # custom route: full freedom
        "GET /public/stats": [],                    # no scopes required
    }
)

Custom scope mappings are additive to the defaults. To override a default, specify the same route pattern with your custom scopes.

An empty scope list removes the permission requirement for that mapping but does not bypass authentication. Unmapped custom REST handlers and arbitrary MCP callable tools need an explicit policy if access requires finer permissions. Built-in MCP tools retain their native scope mappings even when you customize REST mappings.

Built-in routes preserve their native resource namespace. Handlers for /agents, /teams, and /workflows re-check scopes against their native namespace (agents:, teams:, workflows:). Mapping GET /agents to custom:read won't grant access because the handler still requires agents:read. Full freedom applies only to new routes you define yourself.

Next Steps

TaskGuide
Bundle scopes into rolesRoles
Mint machine tokens with scopesService Accounts
Configure JWT middleware in depthJWT Middleware