Authorization 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:
| Operation | Behavior 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 routes | Require session_id and verify the caller owns the run. |
| WebSocket reconnect | Requires 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 and scope checks still apply when user_isolation=False, but routes operate on the unscoped database and add no per-user ownership gates on top of authorization. Per-user isolation requires a database that records user_id (PostgreSQL recommended for production).
Next Steps
| Task | Guide |
|---|
Issue tokens with the sub claim | Tokens |
| See the user isolation cookbook example | user_isolation.py |