Rate limiting¶
Use Configuration as the main guide
for the current Redis-backed auth contract: the RedisAuthPreset flow, stable slot and
group names, namespace defaults and override patterns, and the TOTP Redis-store
setup all live there. This page focuses on the public rate-limit types themselves.
The higher-level one-client Redis preset lives in litestar_auth.contrib.redis.RedisAuthPreset.
This module owns the lower-level shared builder plus the AuthRateLimitSlot enum accepted by
SharedRateLimitConfigOptions.enabled and SharedRateLimitConfigOptions.disabled.
For a smaller public-entry-point preset, AuthRateLimitConfig.strict(backend=...) wires a shared
backend to login, register, and totp_verify using the package default scopes and route-style
namespaces. Pass a backend that already encodes the lower attempt budget you want for those
surfaces.
For internal or lower-risk deployments, AuthRateLimitConfig.lenient(backend=...) uses the
supplied built-in backend for login, refresh, and register, then clones that limiter with a
five-attempt cap for token- and secret-bearing routes such as password reset, verification, and
TOTP. That keeps the broader environment budget off the sensitive recovery and step-up surfaces.
For local development, test harnesses, or other trusted environments that want the plugin wiring
without active throttling, AuthRateLimitConfig.disabled() returns a config where every auth slot
is left unset.
Import the builder aliases and slot enum from litestar_auth.ratelimit when app code annotates
or reuses the shared-backend inventory:
from litestar_auth.ratelimit import (
AuthRateLimitEndpointGroup,
AuthRateLimitSlot,
SharedRateLimitConfigOptions,
)
shared_options = SharedRateLimitConfigOptions(
enabled=tuple(AuthRateLimitSlot),
disabled={AuthRateLimitSlot.VERIFY_TOKEN, AuthRateLimitSlot.REQUEST_VERIFY_TOKEN},
)
AuthRateLimitSlotnames the per-endpoint enum keys accepted bySharedRateLimitConfigOptions.enabled,SharedRateLimitConfigOptions.disabled, andSharedRateLimitConfigOptions.endpoint_overrides.AuthRateLimitEndpointGroupnames the shared-backend keys accepted bySharedRateLimitConfigOptions.group_backends.- Iterate
AuthRateLimitSlotdirectly when you need every supported slot for an explicitSharedRateLimitConfigOptions.enabledvalue. - Use
{AuthRateLimitSlot.VERIFY_TOKEN, AuthRateLimitSlot.REQUEST_VERIFY_TOKEN}forSharedRateLimitConfigOptions.disabledwhen verification routes stay off.
litestar_auth.ratelimit
¶
Rate-limiting helpers for authentication endpoints.
Use :meth:AuthRateLimitConfig.from_shared_backend for direct shared-backend
assembly when one :class:InMemoryRateLimiter or :class:RedisRateLimiter
should back the standard auth endpoint set. For the higher-level one-client
Redis preset that also builds :class:~litestar_auth.totp.RedisTotpEnrollmentStore
and :class:~litestar_auth.totp.RedisUsedTotpCodeStore, see
:class:litestar_auth.contrib.redis.RedisAuthPreset. Keep manual
AuthRateLimitConfig(...) plus EndpointRateLimit(...) assembly for
advanced cases that need fully custom per-endpoint wiring.
Examples:
Build the shared-backend recipe::
from litestar_auth.ratelimit import (
AuthRateLimitConfig,
AuthRateLimitSlot,
RedisRateLimiter,
SharedRateLimitConfigOptions,
)
rate_limit_config = AuthRateLimitConfig.from_shared_backend(
RedisRateLimiter(redis=redis_client, max_attempts=5, window_seconds=60),
options=SharedRateLimitConfigOptions(
disabled={AuthRateLimitSlot.VERIFY_TOKEN, AuthRateLimitSlot.REQUEST_VERIFY_TOKEN},
),
)
AuthRateLimitEndpointGroup = Literal['api_keys', 'login', 'password_reset', 'refresh', 'register', 'totp', 'verification']
¶
RateLimitScope = Literal['api_key_id', 'ip', 'ip_email']
¶
TotpSensitiveEndpoint = Literal['enable', 'confirm_enable', 'verify', 'disable', 'regenerate_recovery_codes']
¶
AuthRateLimitConfig(login=None, change_password=None, refresh=None, register=None, forgot_password=None, reset_password=None, totp_enable=None, totp_confirm_enable=None, totp_verify=None, totp_disable=None, totp_regenerate_recovery_codes=None, verify_token=None, request_verify_token=None, api_key_create=None, api_key_update=None, api_key_use=None)
dataclass
¶
Optional rate-limit rules for auth-related endpoints.
disabled()
classmethod
¶
Build a preset that disables rate limiting for every auth endpoint.
Returns:
| Type | Description |
|---|---|
Self
|
New config with every supported auth slot left unset. |
from_shared_backend(backend, *, options=None)
classmethod
¶
Build endpoint-specific limiters from the package-owned shared-backend recipe.
The builder uses the private endpoint catalog for default scopes and namespace tokens, then applies override precedence in this order:
backendfor every enabled slotgroup_backendsfor slot groups such astotporverificationendpoint_overridesfor full slot replacement or explicitNonedisablement
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
RateLimiterBackend
|
Default limiter backend for enabled auth slots. |
required |
options
|
SharedRateLimitConfigOptions | None
|
Optional shared builder options. Use
|
None
|
Returns:
| Type | Description |
|---|---|
Self
|
New config populated from the shared-backend builder inputs. |
Source code in litestar_auth/ratelimit/_config.py
lenient(*, backend)
classmethod
¶
Build a lenient preset for internal or low-risk deployments.
The supplied backend sets the broader budget used for the lower-risk login, change-password, refresh, and registration surfaces. Token- and secret-bearing flows still receive a stricter built-in limiter clone capped at five attempts per window so reset, verification, and TOTP endpoints do not inherit an overly permissive budget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
RateLimiterBackend
|
Built-in shared backend instance for the lenient preset. |
required |
Returns:
| Type | Description |
|---|---|
Self
|
New config with route-style namespaces for every supported auth slot. |
Source code in litestar_auth/ratelimit/_config.py
strict(*, backend)
classmethod
¶
Build a strict preset for public-facing sign-in surfaces.
The provided backend should already be configured with the lower attempt budget you want to enforce. This preset wires that shared backend to the highest-risk credential entry points: login, change-password, register, and TOTP verify.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
backend
|
RateLimiterBackend
|
Shared backend instance for the strict preset slots. |
required |
Returns:
| Type | Description |
|---|---|
Self
|
New config with only the strict preset slots enabled. |
Source code in litestar_auth/ratelimit/_config.py
AuthRateLimitSlot
¶
Bases: StrEnum
IDE-friendly enum of supported auth rate-limit endpoint slots.
EndpointRateLimit(backend, scope, namespace, trusted_proxy=False, identity_fields=_DEFAULT_IDENTITY_FIELDS, trusted_headers=_DEFAULT_TRUSTED_HEADERS)
dataclass
¶
Per-endpoint rate-limit settings and request hook.
before_request(request)
async
¶
Reject the request with 429 when its key is over the configured limit.
Security
Only set trusted_proxy=True when this service is behind a trusted
proxy or load balancer that overwrites client IP headers. Otherwise,
attackers can spoof headers like X-Forwarded-For and evade or
poison rate-limiting keys.
Raises:
| Type | Description |
|---|---|
TooManyRequestsException
|
If the request exceeded the configured limit. |
Source code in litestar_auth/ratelimit/_endpoint.py
build_key(request)
async
¶
Build the backend key for the given request.
Returns:
| Type | Description |
|---|---|
str
|
Namespaced rate-limit key for the request. |
Source code in litestar_auth/ratelimit/_endpoint.py
increment(request)
async
¶
Record a failed or rate-limited attempt for the current request.
reset(request)
async
¶
SharedRateLimitConfigOptions(enabled=None, disabled=(), group_backends=None, endpoint_overrides=None, trusted_proxy=False, identity_fields=_DEFAULT_IDENTITY_FIELDS, trusted_headers=_DEFAULT_TRUSTED_HEADERS)
dataclass
¶
Shared-backend builder options for auth endpoint rate-limit configs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
Iterable[AuthRateLimitSlot] | None
|
Optional auth slot enum values to build. Defaults to all supported slots. |
None
|
disabled
|
Iterable[AuthRateLimitSlot]
|
Auth slot enum values to leave unset, even when they would otherwise be enabled. |
()
|
group_backends
|
Mapping[AuthRateLimitEndpointGroup, RateLimiterBackend] | None
|
Optional backend overrides keyed by auth slot group. |
None
|
endpoint_overrides
|
Mapping[AuthRateLimitSlot, EndpointRateLimit | None] | None
|
Optional full per-slot replacements. |
None
|
trusted_proxy
|
bool
|
Shared trusted-proxy setting applied to generated limiters. |
False
|
identity_fields
|
tuple[str, ...]
|
Shared request body identity fields applied to generated limiters. |
_DEFAULT_IDENTITY_FIELDS
|
trusted_headers
|
tuple[str, ...]
|
Shared trusted proxy header names applied to generated limiters. |
_DEFAULT_TRUSTED_HEADERS
|
InMemoryRateLimiter(*, max_attempts, window_seconds, max_keys=100000, sweep_interval=1000, clock=time.monotonic)
¶
Async-safe in-memory sliding-window rate limiter.
Not safe for multi-process or multi-host deployments; use :class:RedisRateLimiter
for shared storage (e.g. multi-worker or multi-pod).
Store the limiter configuration and request counters.
Raises:
| Type | Description |
|---|---|
ValueError
|
If any limiter or storage configuration is invalid. |
Source code in litestar_auth/ratelimit/_memory.py
is_shared_across_workers
property
¶
In-memory counters are process-local and not shared across workers.
check(key)
async
¶
Return whether key can perform another attempt.
Source code in litestar_auth/ratelimit/_memory.py
increment(key)
async
¶
Record a new attempt for key in the current window.
Source code in litestar_auth/ratelimit/_memory.py
reset(key)
async
¶
retry_after(key)
async
¶
Return the remaining block duration for key in whole seconds.
Source code in litestar_auth/ratelimit/_memory.py
RedisRateLimiter(*, redis, max_attempts, window_seconds, key_prefix=DEFAULT_KEY_PREFIX, clock=time.time)
¶
Redis-backed sliding-window rate limiter backed by a sorted set.
Store the Redis client and shared rate-limiter configuration.
Source code in litestar_auth/ratelimit/_redis.py
is_shared_across_workers
property
¶
Redis-backed counters are shared across workers using the same Redis.
check(key)
async
¶
Return whether key can perform another attempt.
Source code in litestar_auth/ratelimit/_redis.py
increment(key)
async
¶
Record a new attempt for key atomically in Redis.
Source code in litestar_auth/ratelimit/_redis.py
reset(key)
async
¶
retry_after(key)
async
¶
Return the remaining block duration for key in whole seconds.
Source code in litestar_auth/ratelimit/_redis.py
RateLimiterBackend
¶
TotpRateLimitOrchestrator(enable=None, confirm_enable=None, verify=None, disable=None, regenerate_recovery_codes=None, _ACCOUNT_STATE_RESET_ENDPOINTS=frozenset({'verify'}))
dataclass
¶
Orchestrate TOTP endpoint rate-limit behavior with explicit semantics.
External behavior stays unchanged:
- verify uses before-request checks, increments on invalid attempts, and
resets on success/account-state failures.
- enable and disable do not consume verify counters.
Endpoints that should reset on account-state failures are listed in
_ACCOUNT_STATE_RESET_ENDPOINTS (currently only verify).
before_request(endpoint, request)
async
¶
Run endpoint-specific before-request checks.
Source code in litestar_auth/ratelimit/_orchestrator.py
on_account_state_failure(endpoint, request)
async
¶
Apply endpoint-specific account-state failure behavior.
Source code in litestar_auth/ratelimit/_orchestrator.py
on_invalid_attempt(endpoint, request)
async
¶
Record endpoint-specific invalid attempt failures.
Source code in litestar_auth/ratelimit/_orchestrator.py
on_success(endpoint, request)
async
¶
Apply endpoint-specific success behavior.