Skip to main content
AgentOS security works in layers: JWT authentication at the edge, scope-based authorization per endpoint, per-request component copies, and opt-in per-user data isolation. Network controls and database permissions cover the rest.
Network-layer controls (rate limiting, WAF, IP allowlists, mTLS) live at your reverse proxy or API gateway layer.

Authentication

A production AgentOS sits behind JWT-validating middleware. Tokens can come from the AgentOS control plane, your own backend, or a third-party identity provider. Your service verifies them with the matching public key. See Self-Hosted for BYO and third-party setup.
authorization=True drives both layers:
  • Authentication (this section): requires a valid JWT on protected central routes.
  • Authorization (below): enforces the token’s scopes per endpoint.
A small set of public routes are exempt from the JWT requirement: /, /health, /info, /docs, /redoc, /openapi.json, /docs/oauth2-redirect. Slack, Telegram, and WhatsApp routes use their interface-specific request verification instead of central JWT middleware.

Generate a Verification Key from the Control Plane

1

Toggle JWT authorization

Open os.agno.comAdd OSLive → paste your URL. 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:
Or, if you manage keys via a JWKS file, point AgentOS at it instead:
When tokens are issued by the AgentOS control plane, it keeps the private key and your service only sees the public key. See Generate a Verification Key from the Control Plane for the full walkthrough.

Configure JWTs from Your Backend or IDP

If you’re issuing JWTs from your own backend, or from a third-party identity provider like WorkOS, Auth0, or Okta, pass an AuthorizationConfig:
verification_keys is a list. AgentOS tries each key in order until one verifies the token, so you can accept tokens from multiple issuers at the same time. For key rotation, use a JWKS file instead. With verify_audience=True, AgentOS rejects tokens whose aud claim doesn’t match the expected audience. That expected value defaults to the AgentOS id; set audience to override it when your provider mints a different value. JWT claim names (scopes, sub) are configured on the JWT middleware itself, not on AuthorizationConfig. The defaults (scopes for the scopes claim, sub for the user ID claim) match the tokens minted by the control plane. For the full self-hosted setup including multi-issuer, see Self-Hosted.

Authorization

AgentOS reads the caller’s permissions from a JWT claim (scopes by default). If your provider uses a different name, such as WorkOS’s permissions, set the scopes_claim argument on the JWT middleware. It is not a field on AuthorizationConfig. Endpoints are gated on those scopes. The AgentOS control plane mints each token with the appropriate scopes. Scopes are bundled into roles and assigned to users in the control plane: the AgentOS control plane provides three default roles (owner, admin, member), and custom roles are available on Enterprise. Self-hosters define roles in their identity provider or backend. See the scope reference for the full scope list, Default Roles for what each grants, and Custom Roles to compose your own.

Request isolation

Each run request gets a fresh copy of the agent, team, or workflow it’s hitting. AgentOS calls deep_copy() on the registered component before the run, so mutable per-run state (session-scoped variables, tool execution context, run metadata) never bleeds between concurrent calls. Heavy resources (the database connection, the model client, MCP tool handles) are shared by reference; only the mutable per-run state is isolated. You get cheap concurrency without two requests racing on the same in-memory agent instance. This is on by default for run endpoints. There’s nothing to configure.

User isolation

Per-user data isolation is opt-in. Authorization remains active without it, but user-scoped database reads are not automatically filtered by the JWT subject. A caller with session or memory read scopes can query rows across users unless another restriction applies. For multi-tenant deployments, turn it on:
With user_isolation=True, every non-admin caller gets: Admin callers with the configured admin_scope, which defaults to agent_os:admin, bypass user isolation and receive the unscoped view. Per-user isolation requires a database that records user_id (PostgreSQL recommended for production).

Defaults

See the AuthorizationConfig reference for all configuration options and their defaults.