Rate Limits#

In order to be secure out of the box various rate limits are in place. The rate limit mechanism is backed by a Django cache. Hence, rate limiting will not work properly if you are using the DummyCache.

When rate limits are hit the 429.html template is rendered, alternatively, you can configure a custom handler by declaring a handler429 view in your root URLconf.

Rate limits are consumed by triggering actions, the full list of which is documented below. Per action, the rate can be configured. The rate itself is an amount, per time unit, per either IP address, user or action-specific key.

For example, requesting a password reset is an action that is both limited globally by IP address, as well as per email. Here, the email address used is the specific key.

Danger

Rate limits rely on accurate client IP address detection to function correctly. However, it is not possible for django-allauth to reliably determine the client IP address out of the box because the correct method varies depending on your deployment architecture (direct connections, load balancers, reverse proxies, CDNs, etc.).

The X-Forwarded-For header cannot be used to determine the client IP, as this header can be trivially spoofed by malicious actors, allowing them to completely bypass rate limits.

To ensure rate limits work correctly:

  1. Review and adjust the rate limit configuration settings documented below (ALLAUTH_TRUSTED_PROXY_COUNT, ALLAUTH_TRUSTED_CLIENT_IP_HEADER) to match your security requirements and deployment architecture.

  2. If the settings are not sufficient, override the account adapter’s get_client_ip() method to implement custom logic for extracting the real client IP address from the correct header(s) for your specific infrastructure. See the adapter documentation for guidance on implementing a custom adapter.

Configuration#

ALLAUTH_TRUSTED_PROXY_COUNT (default: 0)

As the X-Forwarded-For header can be spoofed, you need to configure the number of proxies that are under your control and hence, can be trusted. The default is 0, meaning, no proxies are trusted. As a result, the X-Forwarded-For header will be disregarded by default.

ALLAUTH_TRUSTED_CLIENT_IP_HEADER (default: None)

If your service is running behind a trusted proxy that sets a custom header containing the client IP address, specify that header name here. The client IP will be extracted from this header instead of X-Forwarded-For. Examples: "CF-Connecting-IP" (Cloudflare), "X-Real-IP" (nginx).

Deployment Requirements#

The built-in rate limiter stores its state in the Django cache. For reliable enforcement, the following requirements apply:

  • MUST: The configured cache must be shared by all worker processes. For example, LocMemCache is process-local and therefore cannot enforce rate limits across multi-process web workers.

  • MUST: The cache must have sufficient capacity to prevent rate-limit entries from being evicted before their timeout. Eviction discards the recorded request history and can therefore reset a rate limit prematurely.

  • SHOULD: The cache backend should implement cache.add() atomically and provide strongly consistent reads. Without these guarantees, rate limiting still works, but a high volume of concurrent requests may exceed the configured limits.

Testing#

Unless the rate limit is disabled or the default limits are increased, you might run intro problems if you’re running unit tests that are dependant on funcionalities covered by the rate limits. For example, if you’re testing the confirm_email functionality in your unit tests and you’re testing if the verification email is sent twice after requesting it twice, only one of the emails will be sent.