Skip to main content

FastAPI CSRF Protect

Package version Format Python version License Top Languages Size Last commit Documentation

Protect Banner

Features

FastAPI extension that provides stateless Cross-Site Request Forgery (XSRF) Protection support. Aimed to be easy to use and lightweight, we adopt Double Submit Cookie mitigation pattern. If you were familiar with flask-wtf library this extension suitable for you. This extension inspired by fastapi-jwt-auth 😀

  • Storing fastapi-csrf-token in cookies or serve it in template's context

Installation

The easiest way to start working with this extension with pip

pip install fastapi-csrf-protect
# or
uv add fastapi-csrf-protect

Getting Started

The following examples show you how to integrate this extension to a FastAPI App

Example Login Form

from fastapi import FastAPI, Request, Depends
from fastapi.responses import JSONResponse
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")

class CsrfSettings(BaseSettings):
  secret_key: str = "asecrettoeverybody"
  cookie_samesite: str = "none"

@CsrfProtect.load_config
def get_csrf_config():
  return CsrfSettings()

@app.get("/login")
def form(request: Request, csrf_protect: CsrfProtect = Depends()):
  """
  Returns form template.
  """
  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 create_post(request: Request, csrf_protect: CsrfProtect = Depends()):
  """
  Creates a new Post
  """
  await csrf_protect.validate_csrf(request)
  response: JSONResponse = JSONResponse(status_code=200, content={"detail": "OK"})
  csrf_protect.unset_csrf_cookie(response)  # prevent token reuse
  return response

@app.exception_handler(CsrfProtectError)
def csrf_protect_exception_handler(request: Request, exc: CsrfProtectError):
  return JSONResponse(status_code=exc.status_code, content={"detail": exc.message})

How to send the CSRF token in your client code

HTML Form (Server-side rendered)

<form method="post" action="/login">
  <input type="hidden" name="token_key" value="{{ csrf_token }}">
  <!-- other fields -->
</form>

AJAX (JavaScript)

fetch("/items/123", {
  method: "DELETE",
  headers: {
    "X-CSRFToken": getCookie("csrftoken")
  },
  credentials: "include"
});

[!IMPORTANT]

  • The flexible sub-package ignores the token_location setting — tokens from either header or body are always accepted.
  • CSRF token validation still requires a matching CSRF cookie as in the base package.
  • Priority is given to header over body when both are present.

📌 Flexible Mode (fastapi_csrf_protect.flexible)

Some applications combine Server-Side Rendering (SSR) with API endpoints in the same project. For example:

  • SSR pages rendered with Jinja2 templates that use HTML forms (CSRF token in form body)
  • AJAX / API calls (e.g. DELETE, PUT, PATCH) that pass the CSRF token in the HTTP header

The main fastapi-csrf-protect package is opinionated and expects the CSRF token in one location only (either header or body). For hybrid apps, this can be inconvenient.

The flexible sub-package provides a drop-in replacement for CsrfProtect that always accepts CSRF tokens from either the header or the form body, with the following priority:

  • Header: X-CSRFToken
  • Body: token_key (form-data)

When to use flexible

Use fastapi_csrf_protect.flexible if:

  • You have both SSR pages and API endpoints in the same project.
  • Some requests (like DELETE) cannot send a body but still require CSRF validation.
  • You want to avoid maintaining two different CSRF configurations.

If your app only uses one method to send CSRF tokens, stick to the core package for a stricter policy.

Contributions

Prerequisites

  • git - --fast-version-control
  • python 3.9 and above - High-level general-purpose programming language
  • uv - Extremely fast Python package & project manager, written in Rust

The following guide walks through setting up your local working environment using git as distributed version control system and uv as Python package and version manager. If you do not have git installed, run the following command.

Install using Homebrew (Darwin)
brew install git
Install via binary installer (Linux)
  • Debian-based package management
sudo apt install git-all
  • Fedora-based package management
sudo dnf install git-all

If you do not have uv installed, run the following command.

Install using Homebrew (Darwin)
brew install uv
Install using standalone installer (Darwin and Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh

Once you have git distributed version control system installed, you can clone the current repository and install any version of Python above version 3.9 for this project. The following commands help you set up and activate a Python virtual environment where uv can download project dependencies from the PyPI open-sourced registry defined under pyproject.toml file.

Set up environment and synchronize project dependencies
git clone git@github.com:aekasitt/fastapi-csrf-protect.git
cd fastapi-csrf-protect
uv venv --python 3.9.6
source .venv/bin/activate
uv sync --dev

Roadmap

  • Fix CI/CD and GitHub Pages integration
  • Add code samples when setting up and running tests
  • Drop support for Python 3.9 by October, 2025
  • (Syntax 3.9 -> 3.10) Replace Optional[...] with None | ...
  • (Syntax 3.9 -> 3.10) Replace Union[..., ...] with ... | ...
  • Correct front-end samples in README.md
  • Add flexible examples
  • Rewrite Flexible Mode section in README.md
  • Experiment with granian[uvloop] and granian[rloop]

Getting started

To contribute to the project, fork the repository and clone to your local device and install preferred testing dependency pytest Alternatively, run the following command on your terminal to do so:

uv sync --dev

Testing can be done by the following command post-installation:

uv sync --dev --group tests
pytest

Change-logs

  • 0.3.1 Adopt Double Submit Cookie

    :construction: BREAKING CHANGE 0.3.0 -> 0.3.1: generate_csrf marked for deprecation

  • 0.3.2 Add token_location config (either body or header); Unset to prevent token reuse

    :construction: BREAKING CHANGE 0.3.1 -> 0.3.2: validate_csrf is now async

  • 0.3.5 Introduced Pydantic V2 related bug fixed in version 0.3.6; Affects cookie_samesite

  • 0.3.6 Fixed cookie_samesite validation bug introduced in previous version

  • 1.0.0 Remove deprecated generate_csrf, please use generate_csrf_tokens returning tuple

  • 1.0.1 Fix cookie unsetting when configuring lib with cookie Secure and / or SameSite=None

  • 1.0.2 Improve boolean handling for LoadConfig

  • 1.0.3 Failed experiement to integrate mypyc compilation due to dependency injection pattern

  • 1.0.4 Added flexible mode when token_location is omitted and multiple location checks

    :construction: FAILED ROLLOUT 1.0.3 -> 1.0.4: Rolled out with WIP code; immediately deleted version from PyPI

  • 1.0.5 Remove @dataclass leftover from failed experiment; Clarify failure reasons under tests

  • 1.0.6 Fix Stream consumed when submitted tokens via form data, isinstance consumes body

  • 1.0.7 Fix add preverification content submitted in Flexible Mode; Add test selection flags

Run Examples

To run the provided examples, first you must install extra dependencies granian and minijinja Alternatively, run the following command on your terminal to do so

uv sync --group=examples

Running the example utilizing form submission

granian --interface asgi examples.body:app

Running the example utilizing headers via JavaScript

granian --interface asgi examples.header:app

License

This project is licensed under the terms of the MIT license.

Metadata

Release files for fastapi-csrf-protect 1.0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-csrf-protect 1.0.7
File Size Uploaded
fastapi_csrf_protect-1.0.7.tar.gz 207.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-csrf-protect 1.0.7
File Interpreter ABI Platform
fastapi_csrf_protect-1.0.7-py3-none-any.whl Python 3 none any Details

Total release size: 225.7 kB

Release files / fastapi_csrf_protect-1.0.7.tar.gz

Download URL fastapi_csrf_protect-1.0.7.tar.gz
Size 207.3 kB
Tags Source
SHA-256 checksum
How to use checksums
888b15b232625aae5b997fbcf81ef45633a7694f0312a054f1eec6d132b295fb
BLAKE2b-256 checksum
How to use checksums
f61afedbcb4aba24ccc8abfb5d30e08112073c6a9f20b8d88adbdd3051ceedac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.20

Release files / fastapi_csrf_protect-1.0.7-py3-none-any.whl

Download URL fastapi_csrf_protect-1.0.7-py3-none-any.whl
Size 18.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ca3c5b50564af932ac4ed3d06caeed61bf16eed13a31cfe2bdfc3f7c1e8612a3
BLAKE2b-256 checksum
How to use checksums
bf10f248aab919678444723d557da918088e5c737b44e03e3aa4a0ad7afc7dae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.7.20

Release history Release notifications | RSS feed

This release

1.0.7 This release

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

3 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page