Registry / web-framework / starlette-csrf

starlette-csrf

JSON →
library3.0.0pypypi✓ verified 85d ago

Starlette-CSRF is an active Python middleware designed for Starlette and FastAPI applications to mitigate Cross-Site Request Forgery (CSRF) attacks. It implements the Double Submit Cookie technique, providing protection by requiring a secret value to be sent in both a cookie and a request header for unsafe HTTP methods. The library is currently at version 3.0.0 and maintains a steady release cadence, with the latest major update focusing on Python version compatibility and argument handling.

pip install starlette-csrf
INSTALL
IMPORT
SIG · STARLETTE-CSRF
S
starlette-csrf
web-frameworkpythonv3.0.0
Install
2.0s avg
Import
317ms
Disk
19MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v3.0.0 · 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.329s · 20.9MB
glibc
py 3.103.910 runs
installs and imports cleanly · install 2.0s · import 0.304s · 21MB
19MB installed
● package 19MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

CSRFMiddleware
from starlette_csrf import CSRFMiddleware

This quickstart demonstrates how to integrate `CSRFMiddleware` into a FastAPI application. A `GET` request will automatically receive a `csrftoken` cookie and expose the token in `request.state.csrftoken`. For `POST` requests, the client is expected to include this token in an `x-csrftoken` header for successful validation. The example shows how to embed this in an HTML form.

import os import uvicorn from fastapi import FastAPI, Request, Response, Form from starlette.middleware import Middleware from starlette.routing import Route from starlette.responses import HTMLResponse from starlette_csrf import CSRFMiddleware # Ensure you have a strong secret key SECRET_KEY = os.environ.get('STARLETTE_CSRF_SECRET', 'a-very-secret-key-that-you-should-change-in-production') app = FastAPI( middleware=[ Middleware(CSRFMiddleware, secret=SECRET_KEY) ] ) @app.get("/", response_class=HTMLResponse) async def read_root(request: Request): # The CSRF token is automatically set in a cookie on GET requests # and can be accessed via request.state.csrftoken for templates. # In a real application, you'd embed this in your HTML forms. token = request.state.csrftoken if hasattr(request.state, 'csrftoken') else 'No token (GET request initial load)' return f''' <html> <head> <title>CSRF Test</title> </head> <body> <h1>Welcome!</h1> <p>CSRF Token in state (for display only): {token}</p> <form method="post" action="/submit"> <input type="text" name="item" placeholder="Enter item"> <!-- In a real frontend, you'd get this from a cookie or initial GET response --> <input type="hidden" name="x-csrftoken" value="{{request.state.csrftoken}}"> <button type="submit">Submit</button> </form> <script> // For AJAX requests, you'd extract the csrftoken cookie and send it in the header // Example (conceptual, requires frontend JS to read cookie): // const csrfToken = document.cookie.split('; ').find(row => row.startsWith('csrftoken=')).split('=')[1]; // fetch('/submit', { // method: 'POST', // headers: { // 'Content-Type': 'application/x-www-form-urlencoded', // 'x-csrftoken': csrfToken // }, // body: 'item=ajax_test' // }); </script> </body> </html> ''' @app.post("/submit") async def submit_item(item: str = Form(...), response: Response = None): # The middleware automatically validates the token from the 'x-csrftoken' header # If validation fails, it returns a 403 Forbidden before this handler is called. return {"message": f"Item '{item}' received successfully!"} if __name__ == "__main__": # To run: uvicorn your_app_file_name:app --reload # Then open http://127.0.0.1:8000 uvicorn.run(app, host="127.0.0.1", port=8000)
Debug
Known issues
breakingVersion 3.0.0 dropped support for Python 3.7. Users on older Python versions must upgrade or remain on `starlette-csrf<3.0.0`.
fix
Upgrade Python to 3.8 or newer. If unable to upgrade Python, pin `starlette-csrf` to `<3.0.0`.
affects: >=3.0.0
breakingStarting with version 2.0.0, middleware initializer arguments (other than `app` and `secret`) became keyword-only. While this primarily affects direct instantiation, it's a breaking change for custom middleware setups.
fix
Ensure all optional arguments to `CSRFMiddleware` (e.g., `exempt_urls`, `cookie_name`) are passed as keyword arguments, not positional. Standard usage via `app.add_middleware` or `Middleware()` is generally unaffected.
affects: >=2.0.0
gotchaVersion 1.4.4 rewrote the middleware as a pure ASGI middleware, moving away from `starlette.middleware.base.BaseHTTPMiddleware` (which is now deprecated in Starlette). While an improvement, this might affect advanced users who previously extended `CSRFMiddleware` and relied on `BaseHTTPMiddleware`'s internal structure or methods.
fix
If you have custom middleware extending `CSRFMiddleware`, review your implementation for compatibility with the pure ASGI interface. For standard usage, no action is required.
affects: >=1.4.4
Errors
Common errors & fixes
403 Forbidden error on POST requests (or other unsafe methods).
The CSRF token expected in the 'x-csrftoken' header (or the configured header name) does not match the token in the 'csrftoken' cookie, or the header is missing entirely.
fix
Ensure your frontend (HTML form or JavaScript AJAX request) correctly retrieves the `csrftoken` cookie value and sends it in the `x-csrftoken` HTTP header for all unsafe requests (POST, PUT, DELETE, PATCH). For HTML forms, you can inject `request.state.csrftoken` into a hidden input field. For AJAX, read the cookie and set the header manually.
WebSocket connections fail with `AssertionError` or other unexpected errors when `CSRFMiddleware` is applied globally.
The `CSRFMiddleware` is designed for HTTP requests and may not handle WebSocket scopes correctly, leading to internal errors if it processes a WebSocket connection.
fix
Exempt WebSocket routes from CSRF protection by adding them to the `exempt_urls` argument of the `CSRFMiddleware` using a regular expression pattern. Alternatively, wrap the middleware to conditionally apply it only to HTTP scopes, as suggested in some community discussions.
Upgrade
Version history
3.0.0latest on PyPI · released Jun 27, 2023
Audit
Dependencies
starletterequiredCore framework dependency. Compatible with `starlette >=0.14.2` historically, but generally works with recent versions.
itsdangerousrequiredUsed for cryptographic signing of the CSRF token. Compatible with `itsdangerous >=2.0.1,<3.0.0` historically, but generally works with recent versions.
Agent activity
12 hits · last 30 days
node
10
OpenAI (training)
1
Resources
starlette-csrf — pip install starlette-csrf · libregistry