# FastAPI CSRF Protect
[![Package version](https://img.shields.io/pypi/v/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)
[![Format](https://img.shields.io/pypi/format/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)
[![Python version](https://img.shields.io/pypi/pyversions/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)
[![License](https://img.shields.io/pypi/l/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)
[![Top](https://img.shields.io/github/languages/top/aekasitt/fastapi-csrf-protect)](.)
[![Languages](https://img.shields.io/github/languages/count/aekasitt/fastapi-csrf-protect)](.)
[![Size](https://img.shields.io/github/repo-size/aekasitt/fastapi-csrf-protect)](.)
[![Last commit](https://img.shields.io/github/last-commit/aekasitt/fastapi-csrf-protect/master)](.)
[![Protect Banner](static/protect-banner.svg)](https://github.com/aekasitt/fastapi-csrf-protect/blob/master/static/protect-banner.svg)
## 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](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#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
```bash
pip install fastapi-csrf-protect
# or
poetry add fastapi-csrf-protect
```
## Getting Started
The following examples show you how to integrate this extension to a FastAPI App
### Example Login Form
```python
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 import BaseModel
app = FastAPI()
templates = Jinja2Templates(directory="templates")
class CsrfSettings(BaseModel):
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})
```
## Contributions
To contribute to the project, fork the repository and clone to your local device and install preferred testing dependency [pytest](https://github.com/pytest-dev/pytest)
Alternatively, run the following command on your terminal to do so:
```bash
pip install -U poetry
poetry install
```
Testing can be done by the following command post-installation:
```bash
poetry install --with test
pytest
```
## Changelog
### 🚧 Breaking Changes (0.3.0 -> 0.3.1) The double submit update
* The `generate_csrf` method has now been marked for deprecation
* The recommended method is now `generate_csrf_tokens` which returns a tuple of tokens, first unsigned
and the latter signed
* Recommended pattern is for the first token is aimed for returning as part of context
* Recommended pattern is for the signed token to be set in client's cookie completing [Double Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie)
* To prevent token reuse, protected endpoint can unset the signed CSRF Token in client's cookies as
per example code and recommended pattern.
### 🚧 Breaking Changes (0.3.1 -> 0.3.2) The anti-JavaScript update
* New keys are added at setup `token_location` (either `body` or `header`) and `token_key` is key
where form-encoded keeps the csrf token stored, cross-checked with csrf secret in cookies.
* Asynchronous `validate_csrf` method now needs to be awaited therefore protected endpoints need to
be asynchronous as well.
### Error in version 0.3.5 after updating to Pydantic V2
* Made a blunder when updating from Pydantic V1 to Pydantic V2 and caused an error to occur when
setting `cookie_samesite` in settings
* Fixed in version `0.3.6`
### Run Examples
To run the provided examples, first you must install extra dependencies [uvicorn](https://github.com/encode/uvicorn) and [jinja2](https://github.com/pallets/jinja/)
Alternatively, run the following command on your terminal to do so
```bash
poetry install --with examples
```
Running the example utilizing form submission
```bash
uvicorn examples.body:app
```
Running the example utilizing headers via JavaScript
```bash
uvicorn examples.header:app
```
## License
This project is licensed under the terms of the MIT license.
Raw data
{
"_id": null,
"home_page": null,
"name": "fastapi-csrf-protect",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "asynchronous, cross-site request forgery, csrf, fastapi, samesite, starlette, xsrf",
"author": null,
"author_email": "Sitt Guruvanich <aekazitt+github@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/06/cf/5834bba5795422f266aa76f57a98b43ce5bad8f1d80f85eba368218c5ade/fastapi_csrf_protect-0.3.6.tar.gz",
"platform": null,
"description": "# FastAPI CSRF Protect\n\n[![Package version](https://img.shields.io/pypi/v/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)\n[![Format](https://img.shields.io/pypi/format/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)\n[![Python version](https://img.shields.io/pypi/pyversions/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)\n[![License](https://img.shields.io/pypi/l/fastapi-csrf-protect)](https://pypi.org/project/fastapi-csrf-protect)\n[![Top](https://img.shields.io/github/languages/top/aekasitt/fastapi-csrf-protect)](.)\n[![Languages](https://img.shields.io/github/languages/count/aekasitt/fastapi-csrf-protect)](.)\n[![Size](https://img.shields.io/github/repo-size/aekasitt/fastapi-csrf-protect)](.)\n[![Last commit](https://img.shields.io/github/last-commit/aekasitt/fastapi-csrf-protect/master)](.)\n\n[![Protect Banner](static/protect-banner.svg)](https://github.com/aekasitt/fastapi-csrf-protect/blob/master/static/protect-banner.svg)\n\n## Features\n\nFastAPI extension that provides stateless Cross-Site Request Forgery (XSRF) Protection support.\nAimed to be easy to use and lightweight, we adopt [Double Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie) mitigation pattern.\nIf you were familiar with `flask-wtf` library this extension suitable for you.\nThis extension inspired by `fastapi-jwt-auth` \ud83d\ude00\n\n- Storing `fastapi-csrf-token` in cookies or serve it in template's context\n\n## Installation\n\nThe easiest way to start working with this extension with pip\n\n```bash\npip install fastapi-csrf-protect\n# or\npoetry add fastapi-csrf-protect\n```\n\n## Getting Started\n\nThe following examples show you how to integrate this extension to a FastAPI App\n\n### Example Login Form\n\n```python\nfrom fastapi import FastAPI, Request, Depends\nfrom fastapi.responses import JSONResponse\nfrom fastapi.templating import Jinja2Templates\nfrom fastapi_csrf_protect import CsrfProtect\nfrom fastapi_csrf_protect.exceptions import CsrfProtectError\nfrom pydantic import BaseModel\n\napp = FastAPI()\ntemplates = Jinja2Templates(directory=\"templates\")\n\nclass CsrfSettings(BaseModel):\n secret_key: str = \"asecrettoeverybody\"\n cookie_samesite: str = \"none\"\n\n@CsrfProtect.load_config\ndef get_csrf_config():\n return CsrfSettings()\n\n@app.get(\"/login\")\ndef form(request: Request, csrf_protect: CsrfProtect = Depends()):\n \"\"\"\n Returns form template.\n \"\"\"\n csrf_token, signed_token = csrf_protect.generate_csrf_tokens()\n response = templates.TemplateResponse(\n \"form.html\", {\"request\": request, \"csrf_token\": csrf_token}\n )\n csrf_protect.set_csrf_cookie(signed_token, response)\n return response\n\n@app.post(\"/login\", response_class=JSONResponse)\nasync def create_post(request: Request, csrf_protect: CsrfProtect = Depends()):\n \"\"\"\n Creates a new Post\n \"\"\"\n await csrf_protect.validate_csrf(request)\n response: JSONResponse = JSONResponse(status_code=200, content={\"detail\": \"OK\"})\n csrf_protect.unset_csrf_cookie(response) # prevent token reuse\n return response\n\n@app.exception_handler(CsrfProtectError)\ndef csrf_protect_exception_handler(request: Request, exc: CsrfProtectError):\n return JSONResponse(status_code=exc.status_code, content={\"detail\": exc.message})\n\n```\n\n## Contributions\n\nTo contribute to the project, fork the repository and clone to your local device and install preferred testing dependency [pytest](https://github.com/pytest-dev/pytest)\nAlternatively, run the following command on your terminal to do so:\n\n```bash\npip install -U poetry\npoetry install\n```\n\nTesting can be done by the following command post-installation:\n\n```bash\npoetry install --with test\npytest\n```\n\n## Changelog\n\n### \ud83d\udea7 Breaking Changes (0.3.0 -> 0.3.1) The double submit update\n\n* The `generate_csrf` method has now been marked for deprecation\n* The recommended method is now `generate_csrf_tokens` which returns a tuple of tokens, first unsigned\n and the latter signed\n* Recommended pattern is for the first token is aimed for returning as part of context\n* Recommended pattern is for the signed token to be set in client's cookie completing [Double Submit Cookie](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#double-submit-cookie)\n* To prevent token reuse, protected endpoint can unset the signed CSRF Token in client's cookies as\n per example code and recommended pattern.\n\n### \ud83d\udea7 Breaking Changes (0.3.1 -> 0.3.2) The anti-JavaScript update\n\n* New keys are added at setup `token_location` (either `body` or `header`) and `token_key` is key\n where form-encoded keeps the csrf token stored, cross-checked with csrf secret in cookies.\n* Asynchronous `validate_csrf` method now needs to be awaited therefore protected endpoints need to\n be asynchronous as well.\n\n### Error in version 0.3.5 after updating to Pydantic V2\n\n* Made a blunder when updating from Pydantic V1 to Pydantic V2 and caused an error to occur when\n setting `cookie_samesite` in settings\n* Fixed in version `0.3.6`\n\n### Run Examples\n\nTo run the provided examples, first you must install extra dependencies [uvicorn](https://github.com/encode/uvicorn) and [jinja2](https://github.com/pallets/jinja/)\nAlternatively, run the following command on your terminal to do so\n\n```bash\npoetry install --with examples\n```\n\nRunning the example utilizing form submission\n\n```bash\nuvicorn examples.body:app\n```\n\nRunning the example utilizing headers via JavaScript\n\n```bash\nuvicorn examples.header:app\n```\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n",
"bugtrack_url": null,
"license": null,
"summary": "Stateless implementation of Cross-Site Request Forgery (XSRF) Protection by using Double Submit Cookie mitigation pattern",
"version": "0.3.6",
"project_urls": null,
"split_keywords": [
"asynchronous",
" cross-site request forgery",
" csrf",
" fastapi",
" samesite",
" starlette",
" xsrf"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b42c3ed42cecbcdaa97aabea43f8a3853b245fc10b412b74a962d1842f56167a",
"md5": "8169504712b6b798b2a919aa73b525dc",
"sha256": "a0de413d939a7192a210d8d1729468e14e6519d97e202e2cd5614e4a48ff9f25"
},
"downloads": -1,
"filename": "fastapi_csrf_protect-0.3.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8169504712b6b798b2a919aa73b525dc",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 9961,
"upload_time": "2024-09-30T19:33:33",
"upload_time_iso_8601": "2024-09-30T19:33:33.771502Z",
"url": "https://files.pythonhosted.org/packages/b4/2c/3ed42cecbcdaa97aabea43f8a3853b245fc10b412b74a962d1842f56167a/fastapi_csrf_protect-0.3.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "06cf5834bba5795422f266aa76f57a98b43ce5bad8f1d80f85eba368218c5ade",
"md5": "1dde4cc40c9127864cad404164514a1d",
"sha256": "fb9a6e304f5fe42ba4f2c0e4967bd21a2693c4aa89d95cf6f04b2af0287cdb01"
},
"downloads": -1,
"filename": "fastapi_csrf_protect-0.3.6.tar.gz",
"has_sig": false,
"md5_digest": "1dde4cc40c9127864cad404164514a1d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 182553,
"upload_time": "2024-09-30T19:33:35",
"upload_time_iso_8601": "2024-09-30T19:33:35.153413Z",
"url": "https://files.pythonhosted.org/packages/06/cf/5834bba5795422f266aa76f57a98b43ce5bad8f1d80f85eba368218c5ade/fastapi_csrf_protect-0.3.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-09-30 19:33:35",
"github": false,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"lcname": "fastapi-csrf-protect"
}