Skip to main content

FastAPI Cookie Dependencies

Cookies play a vital role in web applications, helping to maintain state, store user preferences, handle sessions, and implement authentication. FastAPI provides elegant tools to work with cookies through its dependency injection system. In this guide, we'll explore how to use FastAPI's cookie dependencies to access, validate, and work with cookies in your applications.

Introduction to Cookies in Web Applications

Before diving into FastAPI's cookie dependencies, let's understand what cookies are:

Cookies are small pieces of data stored in a user's browser. They're sent with every request to the server that set them, allowing the server to maintain state between requests. Common uses include:

  • Session management
  • User authentication
  • Storing user preferences
  • Tracking user behavior

FastAPI makes working with cookies straightforward through its dependency injection system.

Let's start with a simple example of how to access a cookie:

python
from fastapi import FastAPI, Cookie

app = FastAPI()

@app.get("/cookies")
async def read_cookies(ads_id: str | None = Cookie(default=None)):
return {"ads_id": ads_id}

In this example:

  • We import the Cookie dependency from FastAPI
  • We define a path operation function with a parameter that uses the Cookie dependency
  • The parameter name (ads_id) is used as the cookie name to look for
  • We set a default value of None to make the cookie optional

When you access this endpoint, FastAPI will:

  1. Check if there's a cookie named "ads_id" in the request
  2. If it exists, pass its value to the ads_id parameter
  3. If it doesn't exist, use the default value (None)

The response might look like:

json
{
"ads_id": "abc123"
}

Optional vs Required Cookies

By default, cookies with a default parameter are optional:

python
# Optional cookie
async def read_optional_cookie(user_id: str | None = Cookie(default=None)):
return {"user_id": user_id}

To make a cookie required, remove the default value:

python
# Required cookie
async def read_required_cookie(session_token: str = Cookie()):
return {"session_token": session_token}

If the required cookie is missing, FastAPI returns a validation error automatically.

FastAPI automatically validates and converts cookies to the declared type. For example:

python
from fastapi import FastAPI, Cookie
from datetime import datetime

app = FastAPI()

@app.get("/preferences")
async def read_preferences(
theme: str = Cookie(default="light"),
items_per_page: int = Cookie(default=10),
last_visit: datetime | None = Cookie(default=None)
):
return {
"theme": theme,
"items_per_page": items_per_page,
"last_visit": last_visit
}

In this example:

  • theme is expected to be a string
  • items_per_page is converted to an integer
  • last_visit is attempted to be converted to a datetime object

Custom Validation with Pydantic

You can use Pydantic for more complex cookie validation:

python
from fastapi import FastAPI, Cookie, HTTPException
from pydantic import BaseModel, validator
from typing import Optional

app = FastAPI()

class ThemePreference(BaseModel):
name: str

@validator("name")
def validate_theme(cls, value):
valid_themes = ["light", "dark", "system"]
if value not in valid_themes:
raise ValueError(f"Theme must be one of {valid_themes}")
return value

@app.get("/theme")
async def get_theme(theme: str = Cookie(default="light")):
try:
theme_pref = ThemePreference(name=theme)
return {"current_theme": theme_pref.name}
except ValueError:
raise HTTPException(status_code=400, detail="Invalid theme cookie")

Creating Cookies in Responses

While dependencies help you read cookies from requests, you'll often need to set cookies in responses:

python
from fastapi import FastAPI, Cookie, Response

app = FastAPI()

@app.get("/set-cookie")
async def set_cookie(response: Response):
response.set_cookie(key="user_id", value="abc123", max_age=3600)
return {"message": "Cookie set successfully"}

@app.get("/get-cookie")
async def get_cookie(user_id: str | None = Cookie(default=None)):
return {"user_id": user_id}

Important cookie parameters:

  • max_age: Lifetime of the cookie in seconds
  • expires: Alternative to max_age, sets a specific datetime
  • path: URL path where the cookie is valid
  • domain: Domain where the cookie is valid
  • secure: If True, cookie only sent over HTTPS
  • httponly: If True, cookie not accessible via JavaScript
  • samesite: Controls cross-origin requests ('lax', 'strict', 'none')

Real-World Example: Simple Authentication System

Let's create a simple authentication system using cookies:

python
from fastapi import FastAPI, Cookie, Depends, HTTPException, Response
from fastapi.security import APIKeyCookie
import secrets
from typing import Dict

app = FastAPI()

# Simulating a user database
fake_db: Dict[str, Dict] = {
"user1": {"username": "user1", "full_name": "User One"},
"user2": {"username": "user2", "full_name": "User Two"}
}

# Simulating a session database
sessions: Dict[str, str] = {}

# Cookie security scheme
cookie_sec = APIKeyCookie(name="session_token", auto_error=False)

# Dependency to get the current user
async def get_current_user(session_token: str | None = Depends(cookie_sec)):
if not session_token or session_token not in sessions:
raise HTTPException(status_code=401, detail="Not authenticated")

username = sessions[session_token]
return fake_db[username]

@app.post("/login")
async def login(username: str, response: Response):
if username not in fake_db:
raise HTTPException(status_code=400, detail="Invalid username")

# Create a session token
token = secrets.token_hex(16)
sessions[token] = username

# Set cookie
response.set_cookie(
key="session_token",
value=token,
httponly=True,
max_age=1800,
samesite="lax"
)

return {"message": "Successfully logged in"}

@app.get("/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user

@app.post("/logout")
async def logout(
response: Response,
session_token: str | None = Cookie(default=None)
):
if session_token and session_token in sessions:
del sessions[session_token]

response.delete_cookie(key="session_token")
return {"message": "Successfully logged out"}

In this example:

  1. We create a simple login system
  2. When a user logs in, we create a session token and store it in a cookie
  3. The get_current_user dependency checks for a valid session token
  4. The /me endpoint returns the current user using the dependency
  5. The logout endpoint removes the session and deletes the cookie

Security Considerations

When working with cookies, keep these security best practices in mind:

  1. Use HttpOnly flag for sensitive cookies to prevent JavaScript access
  2. Set the Secure flag to ensure cookies are only sent over HTTPS
  3. Apply the SameSite attribute to defend against CSRF attacks
  4. Set appropriate expiration to limit the cookie lifetime
  5. Don't store sensitive data directly in cookies - store a reference instead
  6. Consider using cookie encryption for sensitive values

Here's how to set a secure cookie:

python
@app.get("/set-secure-cookie")
async def set_secure_cookie(response: Response):
response.set_cookie(
key="session",
value="secure_value",
httponly=True,
secure=True,
samesite="lax",
max_age=1800
)
return {"message": "Secure cookie set"}

Summary

FastAPI's cookie dependencies provide a powerful way to work with cookies in your web applications:

  • Use the Cookie dependency to easily access cookie values in your endpoints
  • Take advantage of automatic validation and conversion to Python types
  • Combine cookies with the dependency injection system for complex use cases
  • Set and manage cookies in responses for features like sessions and authentication
  • Follow security best practices to protect your application and users

With these tools, you can implement essential web features like authentication, user preferences, and stateful interactions in your FastAPI applications.

Additional Resources

Exercises

  1. Create a route that sets a cookie to track the last time a user visited your site.
  2. Implement a simple theme switcher that stores the user's theme preference in a cookie.
  3. Build a shopping cart system that stores the cart contents in cookies.
  4. Create a middleware that logs all cookies in incoming requests (for development purposes only).
  5. Implement a cookie-based consent management system for GDPR compliance.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)