Skip to main content
AgentOS validates the JWT on every request, then checks its scopes against the permissions each endpoint requires. This controls who can access and run your agents, teams, and workflows. JWT verification flow

Quick Start

Enable RBAC when initializing AgentOS:
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS


agent = Agent(
    id="my-agent",
    model=OpenAIResponses(id="gpt-5.2"),
)

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

app = agent_os.get_app()

Generate a Verification Key

authorization=True only tells AgentOS to enforce JWT authorization. To verify tokens, AgentOS also needs a public key. Generate one from the control plane and wire it in.
1

Toggle JWT authorization

Enable JWT authorization when connecting a new AgentOS, or later from the OS Settings page.
2

Copy the public key

Copy the public key for your AgentOS from the modal
3

Set the verification key

Set the JWT_VERIFICATION_KEY environment variable to your public key in your .env file or export it directly in your terminal:
export JWT_VERIFICATION_KEY="your-public-key"
Or, if you manage keys via a JWKS file, point AgentOS at it instead:
export JWT_JWKS_FILE="/path/to/jwks.json"
Authorization is now active for your AgentOS.
The control plane only issues RS256 keys, which is also the default. See authorization troubleshooting for common setup issues.

Configuration Options

Configure JWT verification using AuthorizationConfig:
from agno.os import AgentOS
from agno.os.config import AuthorizationConfig

agent_os = AgentOS(
    id="my-agent-os",
    agents=[agent],
    authorization=True,
    authorization_config=AuthorizationConfig(
        verification_keys=["your-jwt-verification-key"],
        algorithm="RS256",
    ),
)
You can also use a JWKS file:
authorization_config=AuthorizationConfig(
    jwks_file="/path/to/jwks.json",
    algorithm="RS256",
)
Or set environment variables:
export JWT_VERIFICATION_KEY="your-public-key"
# or
export JWT_JWKS_FILE="/path/to/jwks.json"

Running AgentOS Independently

The control plane is one way to issue verification keys, not the only way. AgentOS verifies any JWT signed with a key you provide, so you can mint and verify tokens entirely on your own infrastructure.

Issuing tokens

AgentOS verifies tokens but doesn’t issue them. Generate them in your backend or identity provider, signed with the key whose public half or shared secret you set as a verification key. Include the claims from JWT Token Structure; scopes is the claim RBAC checks. Send the token in the Authorization header:
curl -H "Authorization: Bearer $TOKEN" http://localhost:7777/agents
See the Basic RBAC (Symmetric) and Basic RBAC (Asymmetric) examples for generating signed tokens end to end.

Accepting multiple issuers

verification_keys is a list. AgentOS tries each key in order until one verifies the token. Pass a second key to accept tokens from both the Agno control plane and your own backend at the same time.
authorization_config=AuthorizationConfig(
    verification_keys=[
        AGNO_CONTROL_PLANE_PUBLIC_KEY,  # tokens issued by os.agno.com
        YOUR_BACKEND_PUBLIC_KEY,        # tokens minted by your service
    ],
    algorithm="RS256",
)
This keeps the AgentOS UI working through the control plane while your backend mints its own tokens for service-to-service or production traffic. All keys in the list must use the algorithm set in algorithm.

JWT Token Structure

Your JWT tokens should include:
{
  "sub": "user-123",
  "scopes": ["agents:read", "agents:my-agent:run"],
  "exp": 1735689600,
  "iat": 1735603200
}
ClaimRequiredDescription
scopesYesArray of permission scopes
subNoUser ID (extracted as user_id)
session_idNoSession ID for session tracking
audNoAudience (must match AgentOS id when verify_audience=True)
expNoExpiry timestamp. Recommended; expired tokens are rejected.
iatNoIssued-at timestamp.

Example Tokens

Read-only access:
{
  "scopes": ["agents:read", "teams:read", "sessions:read"]
}
Run a specific agent:
{
  "scopes": ["agents:my-agent:run", "agents:my-agent:read", "sessions:write"]
}
Admin access:
{
  "scopes": ["agent_os:admin"]
}

Scope Format

RBAC uses a hierarchical scope format:
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 split across two enforcement layers. Platform scopes are checked by the control plane. AgentOS scopes are checked by your runtime against incoming requests. Any resource:action scope also accepts a resource:<id>:action form to limit access to a specific resource. See Scope Format. The agent_os:admin scope grants full access to every AgentOS endpoint below.

Platform 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:readGET /modelsList available models
config:writePOST /databases/all/migrateRun migrations on all databases
config:writePOST /databases/*/migrateRun migrations on a specific database

Access Prerequisites

A few scopes gate access in the platform. 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:readUse any AgentOS endpoint (the UI loads /config on startup)

Default Roles

Every organization comes with three default roles.
CapabilityOwnerAdministratorMember
Run agents, teams, workflows
Create and update AgentOS resources
Delete AgentOS resources
Create and update AgentOS instances
Delete AgentOS instances
Manage members and roles
Update organization settings
View billing
Update billing
Delete the organization

Custom Roles and Scopes

Custom roles and scopes are available on the Enterprise plan. Book a call or email support@agno.com to enable.
Custom roles require JWT authentication. Without it, scope enforcement is skipped entirely by AgentOS and assigned roles have no effect.
Compose scopes into named roles in the control plane and assign them to users in your organization. Members inherit the scopes of every role assigned to them.

Create a Custom Role

  1. Open the Roles page in the control plane.
  2. Define a role name and select the scopes it grants.
  3. Save the role.

Assign a Role to a User

Open the Organization settings page and assign the role to a user.

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={
        "GET /agents": ["custom:read"],
        "POST /custom/endpoint": ["custom:write"],
        "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.

Per-User Data Isolation

RBAC controls which operations a caller can perform. Per-user data isolation controls which rows a caller can see and write. Opt in with user_isolation=True:
from agno.os import AgentOS
from agno.os.config import AuthorizationConfig

agent_os = AgentOS(
    id="my-agent-os",
    agents=[agent],
    authorization=True,
    authorization_config=AuthorizationConfig(
        verification_keys=["your-jwt-verification-key"],
        algorithm="RS256",
        user_isolation=True,
    ),
)
When enabled, AgentOS uses the JWT sub claim as the user_id for every non-admin caller:
OperationBehavior with user_isolation=True
Reads (sessions, memory, traces)Scoped to the caller’s user_id. Other users’ rows are not returned.
Writes (sessions, memories, traces)user_id is coerced to the caller’s sub. A caller cannot persist rows attributed to another user.
Cancel / resume / continue routesRequire session_id and verify the caller owns the run.
WebSocket reconnectRequires session_id (and workflow_id) for non-admins.
A caller holding admin_scope (default agent_os:admin) bypasses isolation and sees all data. Set a custom override with admin_scope="ops:admin".
Isolation is off by default. JWT/RBAC still apply when user_isolation=False, but routes operate on the unscoped database and add no per-user ownership gates on top of RBAC. Per-user isolation requires a database that records user_id (PostgreSQL recommended for production).

Excluded Routes

These routes are excluded from RBAC checks by default: /, /health, /info, /docs, /redoc, /openapi.json, /docs/oauth2-redirect

Error Responses

Status CodeDescription
401 UnauthorizedMissing or invalid JWT token
403 ForbiddenInsufficient scopes for the requested operation

Examples

Basic RBAC (Symmetric)

Enable RBAC with a shared-secret JWT (HS256)

Basic RBAC (Asymmetric)

Sign with a private key, verify with the public key (RS256)

Per-Agent Permissions

Grant specific permissions to specific agents

Per-User Data Isolation

Scope sessions, memory, and traces per user with user_isolation=True

Developer Resources

JWT Middleware

Configure token sources, claim extraction, and scope checking

AuthorizationConfig Reference

Configuration options for JWT verification

JWTMiddleware Reference

Complete JWT middleware class reference