Rate Limiting
Purpose
Protect endpoints from abuse and overload with per-class limits: the right key, algorithm, window, and store per endpoint type. This is abuse prevention — it throttles how often; it never decides who may (that's backend-authorization).
When to Use
- Whenever the API has public endpoints, auth flows, or expensive operations.
- Not as a substitute for authorization, quotas-as-billing (a product feature), or CAPTCHA (complementary —
captcha-abuse-prevention).
Inputs
- Endpoint inventory with cost/sensitivity (
rest-api-design).
- Deployment shape (single node vs multiple — determines store).
Discovery Questions
- Which endpoints are public-unauthenticated, auth-flow, or expensive?
- What legitimate peak usage must limits not break (retries, mobile refreshes, NAT-shared IPs)?
- Single instance (in-memory store possible) or multiple (shared store, e.g. Redis, required)?
Responsibilities
- Classify endpoints and set limits per class — tight to loose:
- Login: per-account and per-IP (protects both credential stuffing and spraying); lockout/backoff policy coordinated with
backend-authentication.
- Signup: per-IP, low; pairs with CAPTCHA.
- Password reset / OTP request: per-account and per-IP, very tight; OTP verification attempts capped per code.
- Contact forms / public writes: per-IP, low; pairs with CAPTCHA.
- Public search / listing: per-IP moderate; cost-aware for heavy queries.
- Expensive endpoints (exports, reports, media processing, AI calls): per-account, small; consider queueing instead of rejecting (
background-jobs).
- General authenticated API: per-account baseline as a safety net.
- Choose keys deliberately: IP (pre-auth; beware shared NATs/proxies — trust the right forwarded header only from your proxy), account/user ID (post-auth), or composite.
- Choose algorithm (fixed window, sliding window, token bucket) and store (in-memory only for single-node; shared store across instances).
- Define the 429 response in the standard error shape with
Retry-After (backend-error-handling); log/alert on sustained limiting (backend-observability).
Required Workflow
- Classify endpoints into the classes above.
- Set key + limit + window per class, sized against legitimate peaks.
- Pick algorithm + store for the deployment shape.
- Define 429 behavior and monitoring.
- Specify tests: limit trips at N+1, resets after window, keyed correctly (user B unaffected by user A's exhaustion).
Decision Rules
- Rate limiting complements authorization and CAPTCHA — it reduces attempt volume; it must never be the only control on a protected or bot-targeted action.
- Pre-auth endpoints key on IP (imperfect but available); post-auth on account; login on both.
- Multi-instance deployments need a shared store — per-node in-memory limits multiply by instance count.
- Fail open or closed is a decision: auth flows fail closed (limit errors reject); read endpoints may fail open — record the choice.
Rules
- Every public and expensive endpoint has a recorded limit or a recorded reason it doesn't.
- Derive client IP only from your own proxy's trusted header configuration.
- Limits, windows, and stores live in config, not scattered constants.
Anti-Patterns
- One global limit for all endpoints.
- Treating a rate limit as an authorization control ("only 5 tries, so it's protected").
- Per-IP-only login limits (rotating IPs defeat them) or per-account-only (lockout DoS on victims).
- In-memory counters behind a load balancer.
- Trusting
X-Forwarded-For from the public internet.
Validation Checklist
Definition of Done
A recorded per-class rate-limit design — keys, limits, algorithm, store, 429 behavior, monitoring — covering all public/auth/expensive endpoints, with tests, explicitly complementing (never replacing) authorization and CAPTCHA.
Related Skills
captcha-abuse-prevention, backend-authentication, backend-authorization, backend-error-handling, backend-observability, background-jobs, backend-security.
Related Knowledge
../../../knowledge/ (traffic patterns, deployment shape).
Related References
../../../references/backend/abuse/ (limit tables, when populated).
Context Loading Guidance
- Requires: endpoint inventory with classes, deployment shape.
- Does not require: authorization matrix detail, handler code.
- May load:
captcha-abuse-prevention (paired flows), backend-error-handling.
- Stop when: the per-class limit table + tests are recorded.
Token Efficiency Guidance
The endpoint-class × (key, limit, window, store) table is the deliverable; keep algorithm discussion to the chosen one.
1---2name: rate-limiting3description: Use to plan rate limiting per endpoint class — signup, login, password reset, OTP, contact forms, public search, and expensive endpoints — with keys (IP/account/session), algorithms, stores, and 429 behavior. Abuse prevention, not authorization.4---56# Rate Limiting78## Purpose910Protect endpoints from abuse and overload with per-class limits: the right key, algorithm, window, and store per endpoint type. **This is abuse prevention — it throttles *how often*; it never decides *who may* (that's `backend-authorization`).**1112## When to Use1314- Whenever the API has public endpoints, auth flows, or expensive operations.15- **Not** as a substitute for authorization, quotas-as-billing (a product feature), or CAPTCHA (complementary — `captcha-abuse-prevention`).1617## Inputs1819- Endpoint inventory with cost/sensitivity (`rest-api-design`).20- Deployment shape (single node vs multiple — determines store).2122## Discovery Questions2324- Which endpoints are public-unauthenticated, auth-flow, or expensive?25- What legitimate peak usage must limits *not* break (retries, mobile refreshes, NAT-shared IPs)?26- Single instance (in-memory store possible) or multiple (shared store, e.g. Redis, required)?2728## Responsibilities2930- Classify endpoints and set limits per class — tight to loose:31 - **Login**: per-account *and* per-IP (protects both credential stuffing and spraying); lockout/backoff policy coordinated with `backend-authentication`.32 - **Signup**: per-IP, low; pairs with CAPTCHA.33 - **Password reset / OTP request**: per-account and per-IP, very tight; OTP *verification* attempts capped per code.34 - **Contact forms / public writes**: per-IP, low; pairs with CAPTCHA.35 - **Public search / listing**: per-IP moderate; cost-aware for heavy queries.36 - **Expensive endpoints** (exports, reports, media processing, AI calls): per-account, small; consider queueing instead of rejecting (`background-jobs`).37 - **General authenticated API**: per-account baseline as a safety net.38- Choose keys deliberately: IP (pre-auth; beware shared NATs/proxies — trust the right forwarded header only from your proxy), account/user ID (post-auth), or composite.39- Choose algorithm (fixed window, sliding window, token bucket) and store (in-memory only for single-node; shared store across instances).40- Define the 429 response in the standard error shape with `Retry-After` (`backend-error-handling`); log/alert on sustained limiting (`backend-observability`).4142## Required Workflow43441. Classify endpoints into the classes above.452. Set key + limit + window per class, sized against legitimate peaks.463. Pick algorithm + store for the deployment shape.474. Define 429 behavior and monitoring.485. Specify tests: limit trips at N+1, resets after window, keyed correctly (user B unaffected by user A's exhaustion).4950## Decision Rules5152- Rate limiting **complements** authorization and CAPTCHA — it reduces attempt volume; it must never be the only control on a protected or bot-targeted action.53- Pre-auth endpoints key on IP (imperfect but available); post-auth on account; login on both.54- Multi-instance deployments need a shared store — per-node in-memory limits multiply by instance count.55- Fail open or closed is a decision: auth flows fail closed (limit errors reject); read endpoints may fail open — record the choice.5657## Rules5859- Every public and expensive endpoint has a recorded limit or a recorded reason it doesn't.60- Derive client IP only from your own proxy's trusted header configuration.61- Limits, windows, and stores live in config, not scattered constants.6263## Anti-Patterns6465- One global limit for all endpoints.66- Treating a rate limit as an authorization control ("only 5 tries, so it's protected").67- Per-IP-only login limits (rotating IPs defeat them) or per-account-only (lockout DoS on victims).68- In-memory counters behind a load balancer.69- Trusting `X-Forwarded-For` from the public internet.7071## Validation Checklist7273- [ ] Endpoints classified; limits per class recorded (signup, login, reset, OTP, contact, search, expensive covered).74- [ ] Keys chosen per class (IP/account/composite).75- [ ] Algorithm + store fit the deployment shape.76- [ ] 429 shape + `Retry-After` + monitoring defined.77- [ ] Tests: trip, reset, key isolation.78- [ ] Not used as an authorization substitute anywhere.7980## Definition of Done8182A recorded per-class rate-limit design — keys, limits, algorithm, store, 429 behavior, monitoring — covering all public/auth/expensive endpoints, with tests, explicitly complementing (never replacing) authorization and CAPTCHA.8384## Related Skills8586`captcha-abuse-prevention`, `backend-authentication`, `backend-authorization`, `backend-error-handling`, `backend-observability`, `background-jobs`, `backend-security`.8788## Related Knowledge8990`../../../knowledge/` (traffic patterns, deployment shape).9192## Related References9394`../../../references/backend/abuse/` (limit tables, when populated).9596## Context Loading Guidance9798- **Requires:** endpoint inventory with classes, deployment shape.99- **Does not require:** authorization matrix detail, handler code.100- **May load:** `captcha-abuse-prevention` (paired flows), `backend-error-handling`.101- **Stop when:** the per-class limit table + tests are recorded.102103## Token Efficiency Guidance104105The endpoint-class × (key, limit, window, store) table is the deliverable; keep algorithm discussion to the chosen one.