FastAPI CSRF Protect

1.0.7 · active · verified Thu Apr 16

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.

Common errors

Warnings

Install

Imports

Quickstart

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>

view raw JSON →