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 Type | Requests/Minute | Requests/Hour |
|---|---|---|
| Anonymous (by IP) | 60 | 500 |
| Authenticated User | 100 | 1,000 |
| Admin User | 300 | 5,000 |
By Endpoint
| Endpoint | Requests/Minute | Requests/Hour |
|---|---|---|
/api/v1/auth/login | 10 | 50 |
/api/v1/auth/register | 5 | 20 |
/api/v1/auth/forgot-password | 3 | 10 |
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: 980Rate 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=1000Customizing 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:
- Redis Backend — configure
REDIS_ENABLED=truefor distributed rate limiting - Load Balancer — configure rate limiting at the load balancer level
- 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}