🚧 FastCMS is under active development — not ready for production use. APIs and features may change without notice.
FastCMS
Security

Rate Limiting

Per-user and per-IP rate limiting with role-based limits, endpoint-specific rules, and audit integration.

Rate Limiting

FastCMS includes a sophisticated rate limiting system that protects against abuse while providing fair access to all users.

Default Limits

By User Type

User TypeRequests/MinuteRequests/Hour
Anonymous (by IP)60500
Authenticated User1001,000
Admin User3005,000

By Endpoint

EndpointRequests/MinuteRequests/Hour
/api/v1/auth/login1050
/api/v1/auth/register520
/api/v1/auth/forgot-password310

Response Headers

Every API response includes rate limit headers:

X-RateLimit-Limit-Minute: 100
X-RateLimit-Limit-Hour: 1000
X-RateLimit-Remaining-Minute: 95
X-RateLimit-Remaining-Hour: 980

Rate Limit Exceeded Response

HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Please slow down.",
  "details": {
    "limit_per_minute": 100,
    "retry_after_seconds": 60
  }
}

Configuration

RATE_LIMIT_ENABLED=true
RATE_LIMIT_PER_MINUTE=100
RATE_LIMIT_PER_HOUR=1000

Customizing Limits

In app/core/rate_limit.py:

DEFAULT_LIMITS = {
    "anonymous": RateLimitConfig(requests_per_minute=60, requests_per_hour=500),
    "user": RateLimitConfig(requests_per_minute=100, requests_per_hour=1000),
    "admin": RateLimitConfig(requests_per_minute=300, requests_per_hour=5000),
}

ENDPOINT_LIMITS = {
    "/api/v1/auth/login": RateLimitConfig(requests_per_minute=10, requests_per_hour=50),
    "/api/v1/auth/register": RateLimitConfig(requests_per_minute=5, requests_per_hour=20),
}

How It Works

Rate limits are tracked using a sliding window algorithm:

  • Minute window — resets 60 seconds after first request
  • Hour window — resets 3600 seconds after first request

Key generation:

  • JWT users: user:{user_id}
  • API key users: apikey:{hash}
  • Anonymous: ip:{client_ip}

Skipped Paths

The following paths are excluded from rate limiting:

  • /health — health check
  • /docs — API documentation
  • /static/* — static files

Client Handling

async function fetchWithRateLimit(url, options = {}) {
  const response = await fetch(url, options);

  const remaining = response.headers.get('X-RateLimit-Remaining-Minute');
  if (remaining !== null && parseInt(remaining) < 10) {
    console.warn('Approaching rate limit, slowing down...');
    await new Promise(resolve => setTimeout(resolve, 1000));
  }

  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After') || 60;
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    return fetchWithRateLimit(url, options);
  }

  return response;
}

Production Scaling

Rate limit counters are stored in-memory by default. For multiple instances:

  1. Redis Backend — configure REDIS_ENABLED=true for distributed rate limiting
  2. Load Balancer — configure rate limiting at the load balancer level
  3. API Gateway — use an API gateway with built-in rate limiting

Monitoring

Query rate limit violations in audit logs:

GET /api/v1/audit?event_type=security&event_action=rate_limit
Authorization: Bearer {admin_token}

On this page