← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

API Rate Limiting

api_design Intermediate

Also Known As

rate limit throttling token bucket sliding window

TL;DR

Controlling how many requests a client can make in a time window — protecting against abuse, ensuring fair usage, and preventing accidental DoS from misbehaving clients.

Explanation

Rate limiting algorithms: Fixed Window (simple, reset at interval boundary — burst problem), Sliding Window (smoother, no burst at reset), Token Bucket (allows short bursts, refills at constant rate), Leaky Bucket (smooths bursts, constant output rate). Responses should include Retry-After and X-RateLimit-* headers. Rate limits should be keyed by API key, user ID, or IP — IP-based alone is easy to bypass. Differentiate limits by endpoint cost: search is heavier than a GET.

Diagram

flowchart TD
    REQ[API Request] --> CHECK{Rate limit<br/>check}
    CHECK -->|under limit| PROC[Process request]
    CHECK -->|exceeded| BLOCK[429 Too Many Requests<br/>Retry-After header]
    subgraph Algorithms
        FIXED[Fixed Window<br/>100 req per minute]
        SLIDE[Sliding Window<br/>smoother]
        TOKEN[Token Bucket<br/>allows bursts]
        LEAK[Leaky Bucket<br/>constant rate]
    end
    subgraph Limit By
        IP[Per IP]
        USER[Per user/API key]
        ENDPOINT[Per endpoint]
        GLOBAL[Global]
    end
style PROC fill:#238636,color:#fff
style BLOCK fill:#f85149,color:#fff

Watch Out

A fixed-window rate limiter allows double the intended request rate at window boundaries — a client making requests at the end of one window and the start of the next gets 2× quota in a short burst.

Common Misconception

IP-based rate limiting is sufficient — behind shared NAT or office proxies, thousands of users share one IP; use API key or user ID as the primary rate limit key.

Why It Matters

Without rate limiting, a single misbehaving client can exhaust all server resources — rate limiting protects availability for all users and is a first-line defence against credential stuffing.

Common Mistakes

  • Not returning Retry-After header — clients must implement exponential backoff without it.
  • Rate limiting at the application layer instead of at the gateway/nginx level — late-stage limiting still consumes resources.
  • Same rate limit for all endpoints — expensive operations (search, export) need tighter limits than simple GETs.
  • Not returning 429 Too Many Requests — some APIs return 503 or 200, confusing clients about whether to retry.

Avoid When

  • Do not rate limit without telling the client what the limits are — silent 429s cause clients to retry aggressively and worsen the problem.
  • Avoid applying identical limits to all endpoints — a read endpoint and a payment endpoint have very different abuse profiles.
  • Do not rely solely on application-layer rate limiting for DoS protection — volumetric attacks must be absorbed at the gateway or CDN layer.

When To Use

  • Always return Retry-After and X-RateLimit-* headers so well-behaved clients can implement automatic backoff.
  • Apply rate limits at multiple granularities: per IP for unauthenticated traffic, per API key for authenticated traffic.
  • Use a sliding window or token bucket algorithm for smooth limiting — fixed windows allow bursts at window boundaries.

Code Examples

💡 Note
The bad 429 response gives no retry guidance; the client retries immediately and amplifies the load. The fix includes Retry-After and remaining-quota headers so clients back off correctly.
✗ Vulnerable
// No rate limit headers — client cannot implement backoff:
HTTP/1.1 429 Too Many Requests
{"error": "Rate limited"}
// Client has no idea when to retry — exponential backoff from scratch
✓ Fixed
// Rate limit with helpful headers:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711270800
Retry-After: 47
{"type": "rate_limit_exceeded", "retry_after": 47}

Added 15 Mar 2026
Edited 31 Mar 2026
Views 22
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
1 ping W 0 pings T 2 pings F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 8 Perplexity 5 Google 2 Ahrefs 2 Unknown AI 2
crawler 18 crawler_json 1
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Implement per-API-key rate limits in Redis; return X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset headers; respond 429 with Retry-After on exhaustion
📦 Applies To
any web api laravel symfony
🔗 Prerequisites
🔍 Detection Hints
API without rate limiting headers; no differentiation between rate limits for different API key tiers; no 429 response
Auto-detectable: ✓ Yes owasp-zap semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-770

✓ schema.org compliant