Skip to content

API Key Rate Limiting — Controlling Third-Party Client Access by API Key

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about API Key Rate Limiting. We cover key concepts, practical examples, and best practices to help you master this topic.

API key rate limiting applies rate limits based on the API key presented in the request, allowing different clients to have different limits based on their subscription tier or trust level.

What You'll Learn

  • How API key rate limiting differs from IP-based limiting
  • How to extract and validate API keys from requests
  • How to enforce per-key limits with different tiers

Why It Matters

IP-based limiting is unreliable with shared IPs (NAT, VPNs). API key limiting maps traffic to specific clients regardless of their IP address, enabling accurate per-customer tracking, billing based on usage, and tiered access control.

Real-World Use

DodaTech's threat intelligence API provides API keys to partners. Each key has a limit based on the partner's plan: Free tier = 100 req/hr, Pro = 1000 req/hr, Enterprise = 10000 req/hr. API key limiting ensures each partner stays within their plan while preventing one partner's traffic from affecting others.

flowchart LR
    A["Request\n+ API Key"] --> B{"Extract &\nvalidate key"}
    B -->|"Key: free_abc"| C["Free: 100 req/hr"]
    B -->|"Key: pro_xyz"| D["Pro: 1000 req/hr"]
    B -->|"Key: ent_123"| E["Enterprise: 10000 req/hr"]
    C --> F{"Under limit?"}
    D --> F
    E --> F
    F -->|Yes| G["Process Request"]
    F -->|No| H["429 Rate Limited"]
    style B fill:#dbeafe,stroke:#2563eb
    style H fill:#fecaca,stroke:#dc2626

Implementation

import redis
from flask import Flask, request, jsonify, g
from functools import wraps

app = Flask(__name__)
r = redis.Redis(host='localhost', port=6379, db=0)

# API key configuration
API_KEYS = {
    "free_a1b2c3": {"tier": "free", "limit": 100, "window": 3600},
    "pro_d4e5f6": {"tier": "pro", "limit": 1000, "window": 3600},
    "ent_g7h8i9": {"tier": "enterprise", "limit": 10000, "window": 3600},
}

def get_api_key():
    api_key = request.headers.get('X-API-Key')
    if not api_key:
        api_key = request.args.get('api_key')
    return api_key

def require_api_key(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        api_key = get_api_key()
        if not api_key:
            return jsonify({"error": "missing_api_key"}), 401
        if api_key not in API_KEYS:
            return jsonify({"error": "invalid_api_key"}), 403
        g.api_key = api_key
        g.api_key_config = API_KEYS[api_key]
        return f(*args, **kwargs)
    return decorated

def rate_limit_by_api_key():
    api_key = g.api_key
    config = g.api_key_config
    key = f"rl:apikey:{api_key}"
    window = config["window"]
    limit = config["limit"]

    current = r.get(key)
    if current and int(current) >= limit:
        return jsonify({
            "error": "rate_limit_exceeded",
            "tier": config["tier"],
            "limit": limit,
            "retry_after": r.ttl(key)
        }), 429

    pipe = r.pipeline()
    pipe.incr(key)
    pipe.expire(key, window)
    pipe.execute()

@app.route('/api/data')
@require_api_key
def get_data():
    limit_response = rate_limit_by_api_key()
    if limit_response:
        return limit_response
    return jsonify({"data": "response data"})

Tiered Key Management

import secrets
import hashlib

def generate_api_key(prefix="doda"):
    key = secrets.token_urlsafe(32)
    return f"{prefix}_{key}"

def hash_api_key(key):
    return hashlib.sha256(key.encode()).hexdigest()

# Batch create keys
def create_tier_keys(tier, count):
    keys = []
    for i in range(count):
        raw_key = generate_api_key(tier[:3])
        hashed = hash_api_key(raw_key)
        keys.append({"raw": raw_key, "hashed": hashed, "tier": tier})
        print(f"Created {tier} key: {raw_key}")
    return keys

Common Mistakes

1. Storing API Keys in Plain Text

Store hashed API keys in your database. Hash the incoming key before lookup to prevent credential theft from database breaches.

2. Using API Keys Without TLS

API keys are bearer tokens. Anyone intercepting the key can use it. Always enforce HTTPS.

3. Not Allowing Key Rotation

Partners need to rotate compromised keys. Provide an API endpoint or UI for key revocation and regeneration.

4. Rate Limiting by Key Hash Before Validation

Check key validity before applying rate limits. Invalid keys should not count against any limit.

5. Exposing the Key In URLs

API keys in query parameters appear in server logs, browser history, and referrer headers. Use the Authorization header instead.

Practice Questions

  1. Why is API key limiting better than IP limiting for third-party APIs?
  2. How should API keys be stored in the database?
  3. What header should carry the API key?
  4. How do you handle key rotation?
  5. What is the risk of exposing keys in URLs?

Answers

  1. API keys identify clients regardless of IP, enabling accurate per-client tracking. 2. Store hashed keys (SHA-256), not plaintext. 3. The Authorization header or X-API-Key custom header. 4. Provide a revocation/regeneration endpoint. 5. Keys appear in server logs and browser history.

Challenge

Build an API key management system with key generation, hashed storage, rotation support, per-key rate limit configuration, and a middleware that validates, rate-limits, and logs each API request with the key identifier.

FAQ

What is API key rate limiting?

Rate limiting based on the API key presented in the request, allowing per-client limits.

How is API key limiting different from IP limiting?

API key limiting tracks the client identity, not the network address.

Should I store API keys in plaintext?

No. Hash them with SHA-256 before storing.

What tier structure is common for API keys?

Free (low limit), Pro (medium), Enterprise (high limit with burst allowance).

How does API key limiting work with different tiers?

Each key maps to a tier configuration that specifies the limit and window.

Mini Project

Create a complete API key management service with: key generation for different tiers, hashed storage, an admin API for CRUD operations on keys, rate limiting middleware, usage analytics per key, and a dashboard showing current usage vs limits.

What's Next

  • Learn about quota-based limits for daily and monthly usage caps
  • Explore tiered rate limiting for free/pro/enterprise plans
  • Continue to rate limit headers and how clients should interpret them

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro