Registry / web-framework / fastapi-csrf-protect

fastapi-csrf-protect

JSON →
library1.0.7pypypi✓ verified 86d ago

FastAPI CSRF Protect is a FastAPI extension providing stateless Cross-Site Request Forgery (XSRF) protection. It implements the Double Submit Cookie mitigation pattern, similar to `flask-wtf` and inspired by `fastapi-jwt-auth`. The library is designed to be lightweight and easy to use. The current version is 1.0.7, requiring Python 3.9 or newer, and it maintains an active release cadence.

pip install fastapi-csrf-protect
INSTALL
IMPORT
SIG · FASTAPI-CSRF-PROTE
F
fastapi-csrf-protect
web-frameworkpythonv1.0.7
Install
3.9s avg
Import
740ms
Disk
29MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
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
musl
py 3.103.910 runs
installs and imports cleanly · install 0.0s · import 0.772s · 31.4MB
glibc
py 3.103.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>
Debug
Known issues
breakingThe `generate_csrf` function was deprecated in version 0.3.1. It was replaced by `generate_csrf_tokens` which returns both the plain and signed tokens.
fix
Replace `csrf_protect.generate_csrf()` with `csrf_protect.generate_csrf_tokens()` and use the returned `signed_token` for setting the cookie.
affects: 0.3.0 -> 0.3.1
breakingThe `validate_csrf` method became an `async` function.
fix
Ensure that `validate_csrf` is always `await`ed, e.g., `await csrf_protect.validate_csrf(request)`.
affects: 0.3.1 -> 0.3.2
gotchaThe library relies on explicit calls to `validate_csrf`. Simply injecting `CsrfProtect = Depends()` into an endpoint does NOT automatically secure it; you must explicitly call `await csrf_protect.validate_csrf(request)`.
fix
Always include `await csrf_protect.validate_csrf(request)` in any endpoint you intend to protect against CSRF.
affects: All versions
gotchaThe main `fastapi-csrf-protect` package is opinionated and expects the CSRF token in either the header or the body, but not both simultaneously by default. For applications combining Server-Side Rendering (SSR) with API endpoints (hybrid apps), this can be inconvenient.
fix
For hybrid applications, use `from fastapi_csrf_protect.flexible import CsrfProtect`. This sub-package always accepts tokens from either the header (`X-CSRFToken`) or the form body (`token_key`), prioritizing the header if both are present.
affects: All versions
gotchaWhen using cookie-based JWT authentication and sending CSRF tokens as headers, Swagger UI (and other API documentation tools) might fail to send the CSRF header correctly, breaking API documentation for protected endpoints.
fix
Consider documenting how to manually add the CSRF header in tools like Swagger for testing, or use the `flexible` module which handles various token locations, potentially simplifying testing.
affects: All versions
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.
fix
Ensure 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`.
fix
Make 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.
fix
Change 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.
fix
Ensure 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).
Agent activity
17 hits · last 30 days
node
16
OpenAI (training)
1
Resources
fastapi-csrf-protect — pip install fastapi-csrf-protect · libregistry