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.
Basic Cookie Access with FastAPI
Reading a Cookie Value
Let's start with a simple example of how to access a cookie:
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:
- Check if there's a cookie named "ads_id" in the request
- If it exists, pass its value to the
ads_id
parameter - If it doesn't exist, use the default value (
None
)
The response might look like:
{
"ads_id": "abc123"
}
Optional vs Required Cookies
By default, cookies with a default
parameter are optional:
# 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:
# 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.
Advanced Cookie Dependencies
Cookie Validation and Types
FastAPI automatically validates and converts cookies to the declared type. For example:
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 stringitems_per_page
is converted to an integerlast_visit
is attempted to be converted to a datetime object
Custom Validation with Pydantic
You can use Pydantic for more complex cookie validation:
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:
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 secondsexpires
: Alternative to max_age, sets a specific datetimepath
: URL path where the cookie is validdomain
: Domain where the cookie is validsecure
: If True, cookie only sent over HTTPShttponly
: If True, cookie not accessible via JavaScriptsamesite
: Controls cross-origin requests ('lax', 'strict', 'none')
Real-World Example: Simple Authentication System
Let's create a simple authentication system using cookies:
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:
- We create a simple login system
- When a user logs in, we create a session token and store it in a cookie
- The
get_current_user
dependency checks for a valid session token - The
/me
endpoint returns the current user using the dependency - The logout endpoint removes the session and deletes the cookie
Security Considerations
When working with cookies, keep these security best practices in mind:
- Use HttpOnly flag for sensitive cookies to prevent JavaScript access
- Set the Secure flag to ensure cookies are only sent over HTTPS
- Apply the SameSite attribute to defend against CSRF attacks
- Set appropriate expiration to limit the cookie lifetime
- Don't store sensitive data directly in cookies - store a reference instead
- Consider using cookie encryption for sensitive values
Here's how to set a secure cookie:
@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
- FastAPI official documentation on Cookie Parameters
- MDN Web Docs: HTTP Cookies
- OWASP: Session Management Cheat Sheet
Exercises
- Create a route that sets a cookie to track the last time a user visited your site.
- Implement a simple theme switcher that stores the user's theme preference in a cookie.
- Build a shopping cart system that stores the cart contents in cookies.
- Create a middleware that logs all cookies in incoming requests (for development purposes only).
- 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! :)