> ## 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 authentication from an HTTP-only cookie

> Mount login/logout routes on the base FastAPI app, read JWTs from a secure cookie, and enforce AgentOS scopes normally.

Mount login/logout routes on the base FastAPI app, read JWTs from a secure cookie, and enforce AgentOS scopes normally. The smoke proves both the unauthenticated 401 and authenticated 200 paths.

```python cookie_auth.py theme={null}
"""
JWT authentication from an HTTP-only cookie
===========================================

Mount login/logout routes on the base FastAPI app, read JWTs from a secure
cookie, and enforce AgentOS scopes normally. The smoke proves both the
unauthenticated 401 and authenticated 200 paths.

Prerequisites: none for the smoke; HTTPS in production
Run: .venvs/demo/bin/python cookbook/05_agent_os/07_security/cookie_auth.py
Try: GET /auth/cookie, then GET /agents with the returned cookie
"""

import os
from datetime import UTC, datetime, timedelta

import jwt
from agno.agent import Agent
from agno.models.openai import OpenAIResponses
from agno.os import AgentOS
from agno.os.middleware import JWTMiddleware, TokenSource
from fastapi import FastAPI, Response
from fastapi.testclient import TestClient

# ---------------------------------------------------------------------------
# Create cookie-authenticated AgentOS
# ---------------------------------------------------------------------------

OS_ID = "cookie-security-demo"
COOKIE_NAME = "agent_os_token"
JWT_SECRET = os.getenv(
    "JWT_VERIFICATION_KEY", "development-secret-at-least-256-bits-long"
)

base_app = FastAPI()


@base_app.get("/auth/cookie")
async def set_auth_cookie(response: Response) -> dict[str, str]:
    """Stand-in for the successful callback from an identity provider."""
    now = datetime.now(UTC)
    token = jwt.encode(
        {
            "sub": "cookie-user",
            "aud": OS_ID,
            "scopes": ["agents:read", "agents:run"],
            "iat": now,
            "exp": now + timedelta(hours=1),
        },
        JWT_SECRET,
        algorithm="HS256",
    )
    response.set_cookie(
        key=COOKIE_NAME,
        value=token,
        httponly=True,
        secure=True,
        samesite="strict",
        max_age=3600,
    )
    return {"message": "Authentication cookie set"}


@base_app.delete("/auth/cookie")
async def clear_auth_cookie(response: Response) -> dict[str, str]:
    response.delete_cookie(key=COOKIE_NAME)
    return {"message": "Authentication cookie cleared"}


base_app.add_middleware(
    JWTMiddleware,
    verification_keys=[JWT_SECRET],
    algorithm="HS256",
    authorization=True,
    token_source=TokenSource.COOKIE,
    cookie_name=COOKIE_NAME,
    verify_audience=True,
    excluded_route_paths=[
        "/",
        "/health",
        "/info",
        "/docs",
        "/redoc",
        "/openapi.json",
        "/docs/oauth2-redirect",
        "/auth/cookie",
    ],
)

profile_agent = Agent(
    id="profile-agent",
    name="Profile Agent",
    model=OpenAIResponses(id="gpt-5.5"),
)
agent_os = AgentOS(
    id=OS_ID,
    agents=[profile_agent],
    base_app=base_app,
)
app = agent_os.get_app()


def run_smoke() -> dict[str, int]:
    with TestClient(app, base_url="https://testserver") as client:
        unauthenticated = client.get("/agents").status_code
        cookie_response = client.get("/auth/cookie")
        authenticated = client.get("/agents").status_code

    statuses = {
        "set_cookie": cookie_response.status_code,
        "unauthenticated": unauthenticated,
        "authenticated": authenticated,
    }
    assert COOKIE_NAME in cookie_response.cookies
    assert statuses == {
        "set_cookie": 200,
        "unauthenticated": 401,
        "authenticated": 200,
    }, statuses
    return statuses


# ---------------------------------------------------------------------------
# Run the smoke, then serve
# ---------------------------------------------------------------------------

if __name__ == "__main__":
    smoke_statuses = run_smoke()
    for check_name, status_code in smoke_statuses.items():
        print(f"{check_name}: {status_code}")
    print("Production cookies must stay secure, HTTP-only, and CSRF-protected.")
    agent_os.serve(app=app, port=7777)
```

## Run the Example

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

  <Step title="Install dependencies">
    ```bash theme={null}
    uv pip install -U "agno[os]" openai
    ```
  </Step>

  <Step title="Export your OpenAI API key">
    <CodeGroup>
      ```bash Mac/Linux theme={null}
      export OPENAI_API_KEY="your_openai_api_key_here"
      ```

      ```bash Windows theme={null}
      $Env:OPENAI_API_KEY="your_openai_api_key_here"
      ```
    </CodeGroup>
  </Step>

  <Step title="Run the example">
    Save the code above as `cookie_auth.py`, then run:

    ```bash theme={null}
    python cookie_auth.py
    ```
  </Step>
</Steps>

Full source: [cookbook/05\_agent\_os/07\_security/cookie\_auth.py](https://github.com/agno-agi/agno/blob/v3.0.4/cookbook/05_agent_os/07_security/cookie_auth.py)
