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

# JWT Middleware with Authorization Headers

> Complete AgentOS setup with JWT middleware for authentication and parameter injection using Authorization headers

`AuthMiddleware` validates the JWT in the `Authorization` header and injects its claims into endpoint parameters.

<Note>
  `AuthMiddleware` was named `JWTMiddleware` before v2.7. `JWTMiddleware` remains as an alias.
</Note>

## Code

```python jwt_middleware.py theme={null}
from datetime import UTC, datetime, timedelta

import jwt
from agno.agent import Agent
from agno.db.postgres import PostgresDb
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS
from agno.os.middleware.jwt import AuthMiddleware

# JWT Secret (use environment variable in production)
JWT_SECRET = "a-string-secret-at-least-256-bits-long"

# Setup database
db = PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai")


# Define a tool that uses dependencies claims
def get_user_details(dependencies: dict):
    """
    Get the current user's details.
    """
    return {
        "name": dependencies.get("name"),
        "email": dependencies.get("email"),
        "roles": dependencies.get("roles"),
    }


# Create agent
research_agent = Agent(
    id="user-agent",
    model=OpenAIResponses(id="gpt-5.2"),
    db=db,
    tools=[get_user_details],
    instructions="You are a user agent that can get user details if the user asks for them.",
)


agent_os = AgentOS(
    description="JWT Protected AgentOS",
    agents=[research_agent],
)

# Get the final app
app = agent_os.get_app()

# Add auth middleware to the app
# This middleware will automatically inject JWT values into request.state and is used in the relevant endpoints.
app.add_middleware(
    AuthMiddleware,
    verification_keys=[JWT_SECRET], # or use JWT_VERIFICATION_KEY environment variable
    algorithm="HS256",
    user_id_claim="sub",  # Extract user_id from 'sub' claim
    session_id_claim="session_id",  # Extract session_id from 'session_id' claim
    dependencies_claims=["name", "email", "roles"],
    # In this example, we want this middleware to demonstrate parameter injection, not token validation.
    # In production scenarios, you will probably also want token validation. Be careful setting this to False.
    validate=False,
)

if __name__ == "__main__":
    """
    Run your AgentOS with JWT parameter injection.
    
    Test by calling /agents/user-agent/runs with a message: "What do you know about me?"
    """
    # Test token with user_id and session_id:
    payload = {
        "sub": "user_123",  # This will be injected as user_id parameter
        "session_id": "demo_session_456",  # This will be injected as session_id parameter
        "exp": datetime.now(UTC) + timedelta(hours=24),
        "iat": datetime.now(UTC),
        # Dependency claims
        "name": "John Doe",
        "email": "john.doe@example.com",
        "roles": ["admin", "user"],
    }
    token = jwt.encode(payload, JWT_SECRET, algorithm="HS256")
    print("Test token:")
    print(token)
    agent_os.serve(app="jwt_middleware:app", port=7777, reload=True)
```

## Usage

<Steps>
  <Snippet file="create-venv-step.mdx" />

  <Step title="Set Environment Variables">
    ```bash theme={null}
    export OPENAI_API_KEY=your_openai_api_key
    ```
  </Step>

  <Step title="Install dependencies">
    ```bash theme={null}
    uv pip install -U agno openai pyjwt "fastapi[standard]" uvicorn sqlalchemy pgvector psycopg
    ```
  </Step>

  <Step title="Setup PostgreSQL Database">
    ```bash theme={null}
    # Using Docker
    docker run -d \
      --name agno-postgres \
      -e POSTGRES_DB=ai \
      -e POSTGRES_USER=ai \
      -e POSTGRES_PASSWORD=ai \
      -p 5532:5432 \
      pgvector/pgvector:pg17
    ```
  </Step>

  <Step title="Run Example">
    ```bash theme={null}
    python jwt_middleware.py
    ```

    The server will start and print a test JWT token to the console.
  </Step>

  <Step title="Test JWT Authentication">
    **Test with the generated token:**

    ```bash theme={null}
    # Use the token printed in the console
    export TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."

    curl --location 'http://localhost:7777/agents/user-agent/runs' \
        --header 'Content-Type: application/x-www-form-urlencoded' \
        --header "Authorization: Bearer $TOKEN" \
        --data-urlencode 'message=What do you know about me?'
    ```

    **Test without a token:**

    ```bash theme={null}
    curl --location 'http://localhost:7777/agents/user-agent/runs' \
        --header 'Content-Type: application/x-www-form-urlencoded' \
        --data-urlencode 'message=What do you know about me?'
    ```

    This returns 401 with `{"detail": "Authorization header missing"}`. `validate=False` skips signature verification, but a token is still required.

    **Check the AgentOS API docs:**
    Visit [http://localhost:7777/docs](http://localhost:7777/docs) to see all available endpoints.
  </Step>
</Steps>

## How It Works

1. **JWT Generation**: The example creates a test JWT token with user claims
2. **Middleware Setup**: JWT middleware extracts claims from the `Authorization: Bearer <token>` header
3. **Parameter Injection**: The middleware automatically injects:
   * `user_id` from the `sub` claim
   * `session_id` from the `session_id` claim
   * `dependencies` dict with name, email, and roles
4. **Agent Tools**: The agent can access user details through the injected dependencies

## Next Steps

* [JWT Middleware with Cookies](/agent-os/usage/middleware/jwt-cookies)
* [Custom FastAPI with JWT](/agent-os/usage/middleware/custom-fastapi-jwt)
* [JWT Middleware Documentation](/agent-os/middleware/jwt)
