Skip to main content

FastAPI Request Cookies

Introduction

Cookies are small pieces of data stored on the client's browser. They're commonly used to store user preferences, session information, or tracking data across multiple requests. In web applications, cookies allow servers to maintain stateful information in an otherwise stateless HTTP protocol.

FastAPI provides simple and powerful tools to work with cookies in your applications. In this guide, we'll explore how to:

  • Access cookies from incoming requests
  • Validate and process cookie data
  • Send cookies to clients
  • Work with secure cookies
  • Implement practical cookie-based features

Accessing Cookies in FastAPI

FastAPI makes it straightforward to access cookies sent by the client's browser. You can use the cookies attribute of the Request object:

python
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/cookies")
async def read_cookies(request: Request):
return {"cookies": request.cookies}

When a client sends a request with cookies, this endpoint will return all cookies as a dictionary. For example, if the request includes cookies sessionid=abc123 and preference=dark-mode, the response would be:

json
{
"cookies": {
"sessionid": "abc123",
"preference": "dark-mode"
}
}

For more control and validation, FastAPI provides a dedicated Cookie parameter. This approach is type-safe and supports validation:

python
from fastapi import FastAPI, Cookie

app = FastAPI()

@app.get("/cookie-param")
async def read_cookie_param(session_id: str = Cookie(None)):
return {"session_id": session_id}

If the client sends a cookie named session_id, FastAPI will extract its value and pass it to your function. If the cookie doesn't exist, the default value (None in this example) will be used.

Optional vs Required Cookies

You can make cookies either optional or required:

python
from fastapi import FastAPI, Cookie

app = FastAPI()

# Optional cookie
@app.get("/optional-cookie")
async def read_optional_cookie(user_id: str | None = Cookie(default=None)):
if user_id:
return {"user_id": user_id}
return {"message": "No user_id cookie found"}

# Required cookie
@app.get("/required-cookie")
async def read_required_cookie(tracking_id: str = Cookie()):
return {"tracking_id": tracking_id}

For required cookies, if the client doesn't send the cookie, FastAPI will automatically return an error response with a status code of 422 (Unprocessable Entity).

Type Validation

FastAPI validates cookie data based on the type annotation you provide:

python
from fastapi import FastAPI, Cookie

app = FastAPI()

@app.get("/validate-cookie-type")
async def validate_cookie_type(
user_id: int = Cookie(), # Must be convertible to an integer
max_items: int = Cookie(default=10)
):
return {
"user_id": user_id,
"max_items": max_items
}

Advanced Validation with Pydantic

You can implement more complex validation using Pydantic models:

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

app = FastAPI()

class UserSettings(BaseModel):
theme: str
items_per_page: int

@validator("theme")
def validate_theme(cls, v):
if v not in ["light", "dark", "system"]:
raise ValueError("Theme must be 'light', 'dark', or 'system'")
return v

@app.get("/user-settings")
async def read_settings(
theme: str = Cookie(default="system"),
items_per_page: int = Cookie(default=20)
):
try:
settings = UserSettings(theme=theme, items_per_page=items_per_page)
return settings.dict()
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))

Setting Cookies in Responses

FastAPI allows you to set cookies in your responses using the Response object:

python
from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/set-cookie")
def set_cookie(response: Response):
response.set_cookie(
key="session_id",
value="abc123",
max_age=1800, # 30 minutes in seconds
httponly=True # Cookie cannot be accessed via JavaScript
)
return {"message": "Cookie set successfully"}

When setting cookies, you can customize various parameters:

python
from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/set-detailed-cookie")
def set_detailed_cookie(response: Response):
response.set_cookie(
key="user_preference",
value="dark-mode",
max_age=2592000, # 30 days in seconds
expires=2592000, # Alternative to max_age (but less precise)
path="/", # Cookie is valid for all paths
domain=None, # Current domain
secure=True, # Only sent over HTTPS
httponly=True, # Not accessible via JavaScript
samesite="lax" # Controls when cookies are sent with cross-site requests
)
return {"message": "Preference cookie set successfully"}

Working with Secure Cookies

HttpOnly Cookies

To protect against XSS (Cross-Site Scripting) attacks, use httponly=True when setting cookies. This prevents JavaScript from accessing the cookie:

python
from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/set-secure-cookie")
def set_secure_cookie(response: Response):
response.set_cookie(
key="auth_token",
value="very-secure-token",
httponly=True
)
return {"message": "Secure cookie set"}

Secure Cookies

For sensitive information, use secure=True to ensure cookies are only sent over HTTPS connections:

python
@app.get("/set-https-cookie")
def set_https_cookie(response: Response):
response.set_cookie(
key="sensitive_data",
value="confidential-information",
secure=True,
httponly=True
)
return {"message": "HTTPS-only cookie set"}

SameSite Attribute

The samesite attribute helps protect against CSRF (Cross-Site Request Forgery) attacks:

python
@app.get("/set-samesite-cookie")
def set_samesite_cookie(response: Response):
response.set_cookie(
key="csrf_token",
value="token123",
samesite="strict", # Cookie is not sent for cross-site requests
httponly=True
)
return {"message": "SameSite cookie set"}

SameSite options include:

  • "strict": Cookie is only sent for same-site requests
  • "lax": Cookie is sent for same-site requests and top-level navigations with safe HTTP methods
  • "none": Cookie is sent for all requests (requires secure=True)

Deleting Cookies

To delete a cookie, set its expiration to a time in the past:

python
from fastapi import FastAPI, Response

app = FastAPI()

@app.get("/delete-cookie")
def delete_cookie(response: Response):
response.delete_cookie(key="session_id")
return {"message": "Cookie deleted"}

Practical Examples

Remember User Preferences

This example implements a theme preference system using cookies:

python
from fastapi import FastAPI, Request, Response
from fastapi.responses import HTMLResponse

app = FastAPI()

@app.get("/theme", response_class=HTMLResponse)
async def theme_page(request: Request):
theme = request.cookies.get("theme", "light")

html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>Theme Preference</title>
<style>
body {{
font-family: Arial, sans-serif;
background-color: {{"#f0f0f0" if theme == "light" else "#333"}};
color: {{"#333" if theme == "light" else "#f0f0f0"}};
transition: all 0.3s ease;
}}
button {{
padding: 10px;
margin: 10px;
cursor: pointer;
}}
</style>
</head>
<body>
<h1>Current Theme: {theme}</h1>
<button onclick="setTheme('light')">Light Theme</button>
<button onclick="setTheme('dark')">Dark Theme</button>

<script>
function setTheme(theme) {{
document.cookie = `theme=${{theme}}; path=/; max-age=31536000`;
location.reload();
}}
</script>
</body>
</html>
"""
return HTMLResponse(content=html_content)

Simple Authentication System

Here's a basic authentication system using cookies:

python
from fastapi import FastAPI, Response, Request, HTTPException, Depends
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets

app = FastAPI()
security = HTTPBasic()

# In a real app, you'd store this in a database
USERS = {
"admin": "password123"
}

def get_current_user(request: Request):
user_token = request.cookies.get("session_token")
if not user_token or user_token != "admin-secure-token":
raise HTTPException(status_code=401, detail="Invalid authentication")
return "admin"

@app.post("/login")
def login(credentials: HTTPBasicCredentials = Depends(security), response: Response = None):
username = credentials.username
password = credentials.password

if username not in USERS or USERS[username] != password:
raise HTTPException(status_code=401, detail="Invalid credentials")

# In a real app, generate a secure random token
token = "admin-secure-token"

response.set_cookie(
key="session_token",
value=token,
httponly=True,
secure=True,
samesite="strict",
max_age=1800 # 30 minutes
)

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

@app.get("/profile")
def profile(username: str = Depends(get_current_user)):
return {
"message": f"Hello, {username}!",
"status": "authenticated"
}

@app.post("/logout")
def logout(response: Response):
response.delete_cookie(key="session_token")
return {"message": "Successfully logged out"}

Shopping Cart

A cookie-based shopping cart implementation:

python
from fastapi import FastAPI, Request, Response
import json
import base64

app = FastAPI()

@app.get("/cart")
async def view_cart(request: Request):
# Get cart from cookie or initialize empty cart
cart_cookie = request.cookies.get("shopping_cart")

if cart_cookie:
# Decode base64 and parse JSON
try:
cart_json = base64.b64decode(cart_cookie).decode('utf-8')
cart = json.loads(cart_json)
except:
cart = {"items": []}
else:
cart = {"items": []}

return cart

@app.post("/cart/add")
async def add_to_cart(request: Request, response: Response, product_id: int, quantity: int = 1):
# Get existing cart or initialize
cart_cookie = request.cookies.get("shopping_cart")

if cart_cookie:
try:
cart_json = base64.b64decode(cart_cookie).decode('utf-8')
cart = json.loads(cart_json)
except:
cart = {"items": []}
else:
cart = {"items": []}

# Add or update product in cart
product_exists = False
for item in cart["items"]:
if item["product_id"] == product_id:
item["quantity"] += quantity
product_exists = True
break

if not product_exists:
cart["items"].append({
"product_id": product_id,
"quantity": quantity
})

# Encode cart as JSON, then as base64
cart_json = json.dumps(cart)
cart_base64 = base64.b64encode(cart_json.encode('utf-8')).decode('utf-8')

# Set the cookie
response.set_cookie(
key="shopping_cart",
value=cart_base64,
max_age=86400, # 24 hours
httponly=True
)

return {"message": "Product added to cart", "cart": cart}

Summary

Cookies in FastAPI provide a way to maintain state between HTTP requests. In this guide, we've covered:

  • Accessing cookies from incoming requests using both Request.cookies and the Cookie parameter
  • Validating cookie data with type annotations and Pydantic
  • Setting cookies in responses with various security options
  • Working with secure cookies to protect against XSS and CSRF attacks
  • Deleting cookies when they're no longer needed
  • Practical examples including theme preferences, authentication, and shopping carts

Remember that cookies are stored on the client side, so never store sensitive information in cookies without proper encryption. For sensitive data, consider using server-side sessions with only a session identifier stored in cookies.

Additional Resources

Exercises

  1. Create an endpoint that counts how many times a specific user has visited your site using cookies.
  2. Implement a language preference system that uses cookies to remember the user's preferred language.
  3. Create a "remember me" login functionality that sets a long-lived cookie when selected.
  4. Build a simple A/B testing system that randomly assigns users to test groups and stores their group in a cookie.
  5. Implement a secure authentication system with proper CSRF protection using cookies.


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