Install & Compatibility
Where this runs
tested against v1.0.7 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.772s · 31.4MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 3.9s · import 0.708s · 31MB
29MB installed
● package 29MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
CsrfProtect
✓ from fastapi_csrf_protect import CsrfProtect
CsrfProtectError
✓ from fastapi_csrf_protect.exceptions import CsrfProtectError
CsrfProtect (flexible mode)
✓ from fastapi_csrf_protect.flexible import CsrfProtect
Use this import for hybrid applications that need to accept CSRF tokens from both headers and form bodies.
This quickstart demonstrates how to integrate `fastapi-csrf-protect` into a FastAPI application for a login form scenario. It shows how to load CSRF settings, generate and set CSRF cookies for a GET request, and validate the CSRF token on a POST request. It includes basic error handling for `CsrfProtectError`.
import os
from fastapi import FastAPI, Request, Depends
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi_csrf_protect import CsrfProtect
from fastapi_csrf_protect.exceptions import CsrfProtectError
from pydantic_settings import BaseSettings
app = FastAPI()
templates = Jinja2Templates(directory="templates") # Ensure you have a 'templates' directory with 'form.html'
class CsrfSettings(BaseSettings):
secret_key: str = os.environ.get('CSRF_SECRET_KEY', 'a_super_secret_key_for_csrf_protection')
cookie_samesite: str = "lax"
@CsrfProtect.load_config
def get_csrf_config():
return CsrfSettings()
@app.exception_handler(CsrfProtectError)
async def csrf_protect_exception_handler(request: Request, exc: CsrfProtectError):
return JSONResponse(status_code=exc.status_code, content={'detail': exc.message})
@app.get("/login", response_class=HTMLResponse)
async def login_form(request: Request, csrf_protect: CsrfProtect = Depends()):
csrf_token, signed_token = csrf_protect.generate_csrf_tokens()
response = templates.TemplateResponse(
"form.html", {"request": request, "csrf_token": csrf_token}
)
csrf_protect.set_csrf_cookie(signed_token, response)
return response
@app.post("/login", response_class=JSONResponse)
async def process_login(request: Request, csrf_protect: CsrfProtect = Depends()):
await csrf_protect.validate_csrf(request)
# Your login logic here
response: JSONResponse = JSONResponse(status_code=200, content={"detail": "Login successful"})
csrf_protect.unset_csrf_cookie(response) # Optional: prevent token reuse
return response
# To run this, you'll need a 'templates/form.html' file like:
# <form method="post" action="/login">
# <input type="hidden" name="csrf-token" value="{{ csrf_token }}">
# <label for="username">Username:</label>
# <input type="text" id="username" name="username"><br><br>
# <label for="password">Password:</label>
# <input type="password" id="password" name="password"><br><br>
# <input type="submit" value="Submit">
# </form>
Errors
Common errors & fixes
CsrfProtectError: CSRF token invalid
The CSRF token provided in the request (either in the header or form body) does not match the token in the signed cookie, or the cookie is missing/expired. This could also happen if `validate_csrf` was not called.
fixEnsure the client-side code correctly sends the CSRF token (from `generate_csrf_tokens`) in the `X-CSRFToken` header or a form field named `csrf-token`. Verify the `CsrfSettings` (especially `secret_key` and `cookie_samesite`) are correctly configured and that `await csrf_protect.validate_csrf(request)` is present in your endpoint.
AttributeError: 'CsrfProtect' object has no attribute 'secret_key'
The `CsrfSettings` class or the `@CsrfProtect.load_config` decorator was not properly defined or loaded before attempting to use `CsrfProtect`.
fixMake sure you have a `BaseSettings` subclass (e.g., `CsrfSettings`) defining `secret_key` and decorated with `@CsrfProtect.load_config` in your application's startup phase.
RuntimeError: `validate_csrf` must be awaited
You are calling `csrf_protect.validate_csrf(request)` without `await`. This is common after upgrading from versions prior to 0.3.2.
fixChange the call to `await csrf_protect.validate_csrf(request)`.
PydanticValidationError: 1 validation error for CsrfSettings.secret_key
The `secret_key` in your `CsrfSettings` is not being loaded correctly, potentially due to missing environment variable or an empty string being passed.
fixEnsure that `CSRF_SECRET_KEY` environment variable is set in production, or provide a robust default value in your `CsrfSettings` definition, e.g., `secret_key: str = os.environ.get('CSRF_SECRET_KEY', 'a_strong_default_key')`. Upgrade
Version history
1.0.7latest on PyPI · released Sep 16, 2025
Audit
Dependencies
fastapirequiredCore web framework integration.
pydantic-settingsrequiredUsed for configuration management (e.g., CsrfSettings).