> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth Middleware

> Configure AuthMiddleware for JWT validation, claim injection, and RBAC across REST, MCP, and WebSocket connections.

v2.1.0 (Introduced in v2.1.0)

`AuthMiddleware` is the AgentOS authentication layer. It validates JWTs, service-account tokens (`agno_pat_...`), and the OS security key. For JWTs it extracts tokens from Authorization headers or cookies, validates them, and injects `user_id`, `session_id`, and custom claims into your endpoints. This page covers the JWT configuration. For the other two credential types, see [Service Accounts](https://agno-v2.mintlify.site/agent-os/security/authorization/service-accounts.md) and the [security key](https://agno-v2.mintlify.site/agent-os/security/overview.md#security-key).

> [!NOTE]
>
> The class was renamed from `JWTMiddleware` in v2.7. `JWTMiddleware` remains as an alias, so existing `app.add_middleware(JWTMiddleware, ...)` setups keep working.

The middleware provides three main features:

1. **Token Validation**: Validates JWT tokens and handles authentication
2. **Parameter Injection**: Automatically injects user\_id, session\_id, and custom claims into endpoint parameters
3. **RBAC Authorization**: Validates scopes against required permissions for each endpoint

```python auth_middleware_setup.py theme={null}
from agno.os.middleware.jwt import AuthMiddleware

app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-jwt-verification-key"],  # or use JWT_VERIFICATION_KEY environment variable
    algorithm="RS256",  # RS256 for asymmetric keys, HS256 for symmetric
    user_id_claim="sub",  # Extract user_id from 'sub' claim
    session_id_claim="session_id",  # Extract session_id from claim
    dependencies_claims=["name", "email", "roles"],  # Additional claims
    validate=True,  # Enable token validation
    authorization=True,  # Enable RBAC scope checking
    verify_audience=True,  # Verify `aud` claim matches AgentOS ID
)
```

## Coverage Across Surfaces

AgentOS installs a single `AuthMiddleware` instance on the parent app in every authenticated deployment mode. A token accepted on one surface is accepted with identical constraints on the others.

| Surface | How it is covered |
| - | - |
| REST routes | Requests pass through the middleware directly |
| Mounted `/mcp` app | Parent-app middleware runs before the mount dispatches, so the MCP server carries no auth code of its own |
| WebSockets | The middleware publishes its validator, audience, admin scope, and user-isolation settings to `app.state`; WebSocket handshakes validate against the same configuration |

### Credential Dispatch

The middleware resolves each bearer credential in order:

1. Tokens with the `agno_pat_` prefix authenticate as service accounts against the AgentOS database. This happens before JWT validation. Service-account scopes are enforced even when `authorization=False`, since they are ACL data owned by your AgentOS instance.
2. The internal service token, used by the [scheduler](https://agno-v2.mintlify.site/agent-os/scheduler/overview.md) executor to run scheduled jobs.
3. The OS security key, when no JWT source is configured.
4. Anything else is validated as a JWT.

## Token Sources

The middleware supports three token sources:

**Authorization Header**

Extract JWT from `Authorization: Bearer <token>` header.

```python theme={null}
from agno.os.middleware.jwt import AuthMiddleware, TokenSource

app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-key"],
    token_source=TokenSource.HEADER,  # Default
)
```

**HTTP-Only Cookies**

Extract JWT from HTTP-only cookies for web applications.

```python theme={null}
app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-key"],
    token_source=TokenSource.COOKIE,
    cookie_name="access_token",  # Default
)
```

**Both Sources**

Try both header and cookie (header takes precedence).

```python theme={null}
app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-key"],
    token_source=TokenSource.BOTH,
    cookie_name="access_token",  # Default
    token_header_key="Authorization",  # Default
)
```

## JWKS File Support

For environments using RSA keys managed via JWKS (JSON Web Key Set), you can point to a static JWKS file instead of providing raw public keys:

```python jwks_file_setup.py theme={null}
app.add_middleware(
    AuthMiddleware,
    jwks_file="/path/to/jwks.json",
    algorithm="RS256",
    authorization=True,
)
```

The middleware will:

1. Load public keys from the JWKS file at startup
2. Match incoming tokens by their `kid` (key ID) header claim
3. Validate signatures using the appropriate key

### JWKS File Format

The JWKS file should follow the standard format:

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

### Environment Variable

You can also set the JWKS file path via environment variable:

```bash theme={null}
export JWT_JWKS_FILE="/path/to/jwks.json"
```

> [!NOTE]
>
> JWKS keys are tried first (matched by `kid`). If no matching key is found, the middleware falls back to `verification_keys` if provided.

## Parameter Injection

The middleware automatically injects JWT claims into AgentOS endpoints. The following parameters are extracted from tokens and injected into requests:

* `user_id` - User identifier from token claims
* `session_id` - Session identifier from token claims
* `dependencies` - Custom claims for agent tools
* `session_state` - Custom claims for session management

For example, the `/agents/{agent_id}/runs` endpoint automatically uses `user_id`, `session_id`, `dependencies`, and `session_state` from the JWT token when available.

This is useful for:

* Automatically using the `user_id` and `session_id` from your JWT token when running an agent
* Automatically filtering sessions retrieved from `/sessions` endpoints by `user_id` (where applicable)
* Automatically injecting `dependencies` from claims in your JWT token into the agent run, which then is available on tools called by your agent

See the [full example](https://agno-v2.mintlify.site/agent-os/usage/middleware/jwt-middleware.md).

## Security Features

> [!NOTE]
>
> Use strong verification keys, store them securely (not in code), and enable validation in production.

**Token Validation**: When `validate=True`, the middleware:

* Verifies JWT signature using the verification key
* Checks token expiration (`exp` claim)
* Returns 401 errors for invalid/expired tokens

**Audience Verification**: When `verify_audience=True`, the middleware:

* If `audience` is provided, it will validate the token's audience claim matches the expected audience claim
* If `audience` is not provided, it will validate the token's audience claim matches the AgentOS ID
* Optionally set the `audience_claim` to validate a custom audience claim
* Returns 401 for tokens with mismatched audience

> [!TIP]
>
> **HTTP-Only Cookies**: When using cookies:
>
> * Set `httponly=True` to prevent JavaScript access (XSS protection)
> * Set `secure=True` for HTTPS-only transmission
> * Set `samesite="strict"` for CSRF protection

## Local Development

> [!WARNING]
>
> Do not use `validate=False` in production. The middleware decodes claims without verifying the JWT signature.

Skip signature verification in local development, or when an upstream API gateway already validates JWTs.

```python theme={null}
from agno.os.middleware.jwt import AuthMiddleware

app.add_middleware(
    AuthMiddleware,
    validate=False,
)
```

No verification key is required. Claims are extracted from the token but not authenticated.

## RBAC Authorization

Enable Role-Based Access Control (RBAC) to validate JWT scopes against required permissions:

```python jwt_with_rbac.py theme={null}
app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-jwt-key"],
    algorithm="RS256",
    authorization=True,  # Enable RBAC
    verify_audience=True,  # Verify aud matches AgentOS ID
)
```

When `authorization=True`, the middleware:

* Checks the `scopes` claim in JWT tokens
* Validates scopes against required permissions for each endpoint
* Returns 403 Forbidden for insufficient permissions

### Scope Format

| Format | Example | Description |
| - | - | - |
| `resource:action` | `agents:read` | Access all resources |
| `resource:<id>:action` | `agents:my-agent:run` | Access specific resource |
| `resource:*:action` | `agents:*:run` | Wildcard access |
| `agent_os:admin` | `agent_os:admin` | Full admin access |

### Custom Scope Mappings

Override or extend default scope mappings:

```python custom_scope_mappings.py theme={null}
app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-key"],
    authorization=True,
    scope_mappings={
        # Override default
        "GET /agents": ["custom:agents:list"],
        # Add new endpoint
        "POST /custom/action": ["custom:write"],
        # Allow without scopes
        "GET /public": [],
    }
)
```

> [!TIP]
>
> For all available scopes and default endpoint mappings, see [Scopes](https://agno-v2.mintlify.site/agent-os/security/authorization/scopes.md).

## User Isolation

RBAC controls which endpoints a caller can hit. User isolation controls which rows they can see and mutate. The two are independent toggles.

```python jwt_with_user_isolation.py theme={null}
app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-jwt-key"],
    authorization=True,
    user_isolation=True,
)
```

When `user_isolation=True`, non-admin callers are scoped to the `user_id` from the JWT `sub` claim across sessions, memories, traces, approvals, and other user-owned AgentOS resources. Callers holding `admin_scope` bypass isolation. See [Per-User Data Isolation](https://agno-v2.mintlify.site/agent-os/security/authorization/user-isolation.md) for the full behavior.

## Excluded Routes

These routes skip JWT and RBAC checks by default:

```python theme={null}
["/", "/health", "/info", "/docs", "/redoc", "/openapi.json", "/docs/oauth2-redirect"]
```

Override them with `excluded_route_paths`:

```python jwt_excluded_routes.py theme={null}
app.add_middleware(
    AuthMiddleware,
    verification_keys=["your-key"],
    excluded_route_paths=[
        "/health",
        "/auth/login",
        "/auth/register",
        "/public/*",  # Wildcards supported
    ]
)
```

> [!WARNING]
>
> `excluded_route_paths` replaces the defaults. Re-include any default routes you want to keep.

## Configuration Options

See the [AuthMiddleware reference](https://agno-v2.mintlify.site/reference/agent-os/jwt-middleware.md) for the complete list of configuration options.

### Authentication Options

| Parameter | Description | Default |
| - | - | - |
| `verification_keys` | List of keys for JWT verification. For RS256, use public keys. For HS256, use shared secrets. Each key is tried in order until one succeeds. | `JWT_VERIFICATION_KEY` env var |
| `jwks_file` | Path to a static JWKS file containing public keys. Keys are matched by `kid` from the JWT header. | `JWT_JWKS_FILE` env var |
| `secret_key` | **(Deprecated)** Use `verification_keys` instead. | - |
| `algorithm` | JWT algorithm (RS256, HS256, ES256, etc.) | `"RS256"` |
| `validate` | Enable token validation | `True` |
| `security_key` | Static OS security key credential. Only consulted when no JWT source is configured. | `None` |
| `service_account_verifier` | Verifier for `agno_pat_` service-account tokens. Falls back to `app.state.service_account_verifier`, which AgentOS sets whenever a database is configured. | `None` |

> [!NOTE]
>
> Constructing the middleware requires at least one credential source: a JWT key source (`verification_keys`, `jwks_file`, or their environment variables), `validate=False`, a `security_key`, or a `service_account_verifier`. `authorization=True` also requires a JWT source (verification keys, a JWKS file, or `validate=False` for unverified dev mode).

### Token Source Options

| Parameter | Description | Default |
| - | - | - |
| `token_source` | Where to extract token from: `HEADER`, `COOKIE`, or `BOTH` | `TokenSource.HEADER` |
| `token_header_key` | Header key for Authorization (when using HEADER or BOTH) | `"Authorization"` |
| `cookie_name` | Cookie name (when using COOKIE or BOTH) | `"access_token"` |

### Claim Extraction Options

| Parameter | Description | Default |
| - | - | - |
| `user_id_claim` | JWT claim for user ID | `"sub"` |
| `session_id_claim` | JWT claim for session ID | `"session_id"` |
| `scopes_claim` | JWT claim for scopes | `"scopes"` |
| `audience_claim` | JWT claim for audience/OS ID | `"aud"` |
| `dependencies_claims` | List of claims to extract for `dependencies` parameter | `None` |
| `session_state_claims` | List of claims to extract for `session_state` parameter | `None` |

### Authorization Options (RBAC)

| Parameter | Description | Default |
| - | - | - |
| `authorization` | Enable RBAC scope checking. Auto-enabled when `scope_mappings` is provided. | `None` |
| `verify_audience` | Verify `aud` claim matches AgentOS ID | `False` |
| `audience` | Expected audience claim to validate against the token's audience claim | `AgentOS ID` |
| `user_isolation` | Opt in to per-user isolation for user-owned data and resources throughout AgentOS. When `True`, AgentOS uses the JWT `sub` claim as the `user_id` for every non-admin caller: user-owned reads are scoped to it and user-owned writes are coerced to it. Callers holding `admin_scope` bypass isolation. | `False` |
| `scope_mappings` | Custom route-to-scope mappings (additive to defaults) | `None` |
| `admin_scope` | Scope that grants full admin access | `"agent_os:admin"` |
| `excluded_route_paths` | Routes to skip JWT/RBAC checks | See [Excluded Routes](#excluded-routes) |

## Examples

> **[JWT with Headers](https://agno-v2.mintlify.site/agent-os/usage/middleware/jwt-middleware.md)**
>
> JWT authentication using Authorization headers for API clients.

> **[JWT with Cookies](https://agno-v2.mintlify.site/agent-os/usage/middleware/jwt-cookies.md)**
>
> JWT authentication using HTTP-only cookies for web applications.

> **[Custom FastAPI + JWT](https://agno-v2.mintlify.site/agent-os/usage/middleware/custom-fastapi-jwt.md)**
>
> Custom FastAPI app with JWT middleware and AgentOS integration.

> **[Authorization](https://agno-v2.mintlify.site/agent-os/security/authorization/overview.md)**
>
> Scopes, roles, and access control configuration.

> **[AuthMiddleware Reference](https://agno-v2.mintlify.site/reference/agent-os/jwt-middleware.md)**
>
> Complete auth middleware class reference.

## External Resources

> **[PyJWT Documentation](https://pyjwt.readthedocs.io/)**
>
> Official PyJWT library documentation for JWT encoding and decoding.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.