AuthMiddleware

Parameter reference for AuthMiddleware (aliased as JWTMiddleware), the AgentOS authentication and RBAC middleware.

AuthMiddleware is the AgentOS authentication middleware. It handles JWTs, service account tokens (agno_pat_...), the internal service token, and the OS security key, with optional RBAC (Role-Based Access Control) for JWTs. JWTMiddleware still works as an alias for the manual app.add_middleware(JWTMiddleware, ...) setup path.

Import

from agno.os.middleware.jwt import AuthMiddleware
from agno.os.middleware import JWTMiddleware  # alias of AuthMiddleware
from agno.os.middleware.jwt import TokenSource

Configure at least one credential source: JWT verification keys/JWKS, a service-account verifier, or a security key. Enabling JWT RBAC (authorization=True, including automatic enablement through scope_mappings) requires a JWT source; a PAT verifier or security key alone is insufficient.

AuthMiddleware Parameters

ParameterTypeDefaultDescription
app-RequiredThe FastAPI app instance. Supplied automatically by app.add_middleware
verification_keysOptional[List[str]]NoneExplicit JWT verification keys. If JWT_VERIFICATION_KEY is set, its value is appended even when this list is supplied. Unset the environment variable to stop trusting that key. Each key is tried in order.
jwks_fileOptional[str]JWT_JWKS_FILE env varPath to a static JWKS (JSON Web Key Set) file. Keys are looked up by kid (key ID) from the JWT header.
algorithmstr"RS256"JWT algorithm (RS256, HS256, ES256, etc.)
validateboolTrueVerify token signatures and reject invalid or expired tokens. False skips signature, expiry, and audience validation, producing unverified claims. Use only behind a trusted upstream validator or in isolated development.
authorizationOptional[bool]NoneEnable RBAC scope checking. If left None and scope_mappings is provided, RBAC is auto-enabled.
token_sourceTokenSourceTokenSource.HEADERWhere to extract JWT token from
token_header_keystr"Authorization"Header key for Authorization
cookie_namestr"access_token"Cookie name for JWT token
scopes_claimstr"scopes"JWT claim name for scopes
user_id_claimstr"sub"JWT claim name for user ID
session_id_claimstr"session_id"JWT claim name for session ID
audience_claimstr"aud"JWT claim name for audience/OS ID
audienceOptional[Union[str, Iterable[str]]]NoneExpected audience(s) to validate the token's aud claim against. Accepts a string or a list of strings; the token matches if its audience matches any of them. Defaults to the AgentOS ID.
verify_audienceboolFalseVerify aud claim matches AgentOS ID
dependencies_claimsOptional[List[str]]NoneClaims to extract for dependencies parameter
session_state_claimsOptional[List[str]]NoneClaims to extract for session_state parameter
scope_mappingsOptional[Dict[str, List[str]]]NoneCustom route-to-scope mappings (additive to defaults)
excluded_route_pathsOptional[List[str]]See belowRoutes that bypass all AuthMiddleware authentication, authorization, and request-state population.
admin_scopeOptional[str]NoneScope that grants full admin access. Defaults to "agent_os:admin" when unset
user_isolationboolFalseOpt-in isolation for non-admin JWT callers, using user_id_claim (sub by default). Non-admin service accounts are always scoped to their own principal, regardless of this flag. Admins bypass this isolation.
service_account_verifierOptional[ServiceAccountVerifier]NoneVerifier for service account tokens (agno_pat_...). When set, bearer tokens with the agno_pat_ prefix authenticate as service accounts: user_id is the account principal (sa:<name>) and scopes are the account's stored scopes, enforced against scope mappings even when authorization is disabled.
security_keyOptional[str]NoneStatic OS security key. When no JWT source is configured, bearer tokens are compared against this key and matching requests are authenticated.

TokenSource Enum

ValueDescription
TokenSource.HEADERExtract JWT from Authorization: Bearer <token> header
TokenSource.COOKIEExtract JWT from HTTP cookie
TokenSource.BOTHTry header first, then cookie as fallback

Default Excluded Routes

[
    "/",
    "/health",
    "/info",
    "/docs",
    "/redoc",
    "/openapi.json",
    "/docs/oauth2-redirect",
]

Usage

Basic JWT Validation

Install uv pip install 'agno[os]' openai pyjwt, export OPENAI_API_KEY, and set JWT_SIGNING_KEY to your HS256 issuer's secret. This example uses the same secret for verification. For a complete local token and request example, see middleware setup.

Save as jwt_server.py:

import os

from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS
from agno.os.middleware import JWTMiddleware

verification_key = os.environ["JWT_SIGNING_KEY"]
agent_os = AgentOS(
    id="jwt-reference",
    agents=[Agent(id="assistant", model=OpenAIResponses(id="gpt-5.4"))],
)
app = agent_os.get_app()
app.add_middleware(
    JWTMiddleware,
    verification_keys=[verification_key],
    algorithm="HS256",
    validate=True,
)
uv run uvicorn jwt_server:app --host 0.0.0.0 --port 7777

The following are alternative middleware composition fragments. Replace the app.add_middleware(...) call above with one of them before starting the app; do not stack all the examples.

JWT with RBAC Authorization

app.add_middleware(
    JWTMiddleware,
    verification_keys=[verification_key],
    algorithm="HS256",
    authorization=True,
    audience="jwt-reference",
    verify_audience=True,
)

JWT from Cookies

from agno.os.middleware.jwt import TokenSource

app.add_middleware(
    JWTMiddleware,
    verification_keys=[verification_key],
    algorithm="HS256",
    token_source=TokenSource.COOKIE,
    cookie_name="access_token",
)

Parameter Injection

app.add_middleware(
    JWTMiddleware,
    verification_keys=[verification_key],
    algorithm="HS256",
    user_id_claim="sub",
    session_id_claim="session_id",
    dependencies_claims=["name", "email", "roles"],
    session_state_claims=["preferences"],
)

Using JWKS File

# Using a static JWKS file (e.g., from your identity provider)
app.add_middleware(
    JWTMiddleware,
    jwks_file="/path/to/jwks.json",
    algorithm="RS256",
    authorization=True,
)

Use a real issuer JWKS file. The following shows its shape only; the abbreviated modulus is not a usable key:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "my-key-id",
      "use": "sig",
      "alg": "RS256",
      "n": "0vx7agoebGc...",
      "e": "AQAB"
    }
  ]
}

Custom Scope Mappings

app.add_middleware(
    JWTMiddleware,
    verification_keys=[verification_key],
    algorithm="HS256",
    authorization=True,
    scope_mappings={
        # Override default scope
        "GET /agents": ["custom:agents:list"],
        # Add new endpoint
        "POST /custom/action": ["custom:write"],
        # Allow without scopes
        "GET /public": [],
    }
)

Request State

State fields depend on the authentication path. Excluded routes and OPTIONS requests return before authentication and do not receive these fields.

Authentication pathPopulated fields
JWTauthenticated, user_id, session_id, scopes, claims, audience, token, and authorization_enabled. dependencies, session_state, and accessible_resource_ids are added only when configured or applicable. Factories read JWT claims as ctx.trusted.claims.
Service account token (agno_pat_...)authenticated, user_id, session_id, scopes, authorization_enabled, service_account_name, and authorization metadata. Service account requests do not include claims or token.
Internal scheduler tokenauthenticated, user_id, session_id, scopes, authorization_enabled, and scheduler authorization metadata.
Security keyauthenticated only.

Error Responses

Status CodeDescription
401 UnauthorizedMissing or invalid JWT token
401 UnauthorizedToken has expired (when validation is enabled)
401 UnauthorizedInvalid audience (when validation and audience verification are enabled)
403 ForbiddenInsufficient scopes for the requested operation
429 Too Many RequestsService account verification is rate limited
503 Service UnavailableService account verification is unavailable

See Also