From 0c2fe1272bea766a111412d6aea82851ca44e7a5 Mon Sep 17 00:00:00 2001 From: Trenton H <797416+stumpylog@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:26:09 -0700 Subject: [PATCH] Adds scoped rate limiting to the token API --- docs/configuration.md | 8 ++++++++ pyproject.toml | 2 ++ src/paperless/settings/__init__.py | 3 +++ src/paperless/views.py | 3 +++ 4 files changed, 16 insertions(+) diff --git a/docs/configuration.md b/docs/configuration.md index a22171ce9..3ab1903fc 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -770,6 +770,14 @@ If both the [PAPERLESS_ACCOUNT_DEFAULT_GROUPS](#PAPERLESS_ACCOUNT_DEFAULT_GROUPS Defaults to 1209600 (2 weeks) +#### [`PAPERLESS_TOKEN_THROTTLE_RATE=`](#PAPERLESS_TOKEN_THROTTLE_RATE) {#PAPERLESS_TOKEN_THROTTLE_RATE} + +: Rate limit for the API token authentication endpoint (`/api/token/`), used to mitigate brute-force login attempts. +Uses Django REST Framework's [throttle rate format](https://www.django-rest-framework.org/api-guide/throttling/#setting-the-throttling-policy), +e.g. `5/min`, `100/hour`, `1000/day`. + + Defaults to `5/min` + ## OCR settings {#ocr} Paperless uses [OCRmyPDF](https://ocrmypdf.readthedocs.io/en/latest/) diff --git a/pyproject.toml b/pyproject.toml index 5af886f0c..30c707e09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -318,6 +318,8 @@ markers = [ PAPERLESS_DISABLE_DBHANDLER = "true" PAPERLESS_CACHE_BACKEND = "django.core.cache.backends.locmem.LocMemCache" PAPERLESS_CHANNELS_BACKEND = "channels.layers.InMemoryChannelLayer" +# I don't think anything hits this, but just in case, basically infinite +PAPERLESS_TOKEN_THROTTLE_RATE = "1000/min" [tool.coverage.report] exclude_also = [ diff --git a/src/paperless/settings/__init__.py b/src/paperless/settings/__init__.py index 3522b3187..d51be67db 100644 --- a/src/paperless/settings/__init__.py +++ b/src/paperless/settings/__init__.py @@ -161,6 +161,9 @@ REST_FRAMEWORK = { "ALLOWED_VERSIONS": ["9", "10"], # DRF Spectacular default schema "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", + "DEFAULT_THROTTLE_RATES": { + "login": os.getenv("PAPERLESS_TOKEN_THROTTLE_RATE", "5/min"), + }, } if DEBUG: diff --git a/src/paperless/views.py b/src/paperless/views.py index a3b965f3f..e4db40bb4 100644 --- a/src/paperless/views.py +++ b/src/paperless/views.py @@ -34,6 +34,7 @@ from rest_framework.pagination import PageNumberPagination from rest_framework.permissions import DjangoModelPermissions from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response +from rest_framework.throttling import ScopedRateThrottle from rest_framework.viewsets import ModelViewSet from documents.permissions import PaperlessObjectPermissions @@ -51,6 +52,8 @@ from paperless_ai.indexing import vector_store_file_exists class PaperlessObtainAuthTokenView(ObtainAuthToken): serializer_class = PaperlessAuthTokenSerializer + throttle_classes = [ScopedRateThrottle] + throttle_scope = "login" class StandardPagination(PageNumberPagination):