[SEC] Sliding Window Rate Limiting with Adaptive Limits
Priority: High
Difficulty: Hard
Estimated Effort: 2-3 days
Relevant Packages: OrbitStream_backend/
Labels: security, enhancement, priority:high
Requirements
1. Sliding Window Implementation
Use Redis sorted sets for a true sliding window (not fixed window which allows 2x burst):
-- Lua script for atomic sliding window
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])
-- Remove expired entries
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
-- Count current entries
local count = redis.call('ZCARD', key)
if count < limit then
redis.call('ZADD', key, now, now .. math.random())
redis.call('EXPIRE', key, window)
return {limit - count - 1, 0} -- remaining, retry_after
else
local oldest = redis.call('ZRANGE', key, 0, 0, 'WITHSCORES')
local retry_after = math.ceil(tonumber(oldest[2]) + window - now)
return {0, retry_after} -- remaining, retry_after
end
2. Per-Endpoint Limits
| Endpoint |
Limit |
Window |
/auth/login |
5 requests |
1 minute |
/auth/verify |
10 requests |
1 minute |
/merchants/register |
3 requests |
1 minute |
/v1/checkout/sessions (POST) |
100 requests |
1 minute |
/v1/checkout/sessions/:id (GET) |
60 requests |
1 minute |
| All other endpoints |
60 requests |
1 minute |
3. Per-Auth-Type Multipliers
- Unauthenticated: 1x base limit
- JWT-authenticated: 2x base limit
- API-key-authenticated: 5x base limit
- Admin: 10x base limit
4. Adaptive Limits
If a merchant has >10 successful payments in the last hour, increase their checkout creation limit by 50%. Check using a Redis counter orbitstream:merchant_payments:{id}:{hour}.
5. Response Headers
Every response includes:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200 (Unix timestamp when window resets)
6. 429 Response
{
"statusCode": 429,
"message": "Rate limit exceeded",
"error": "Too Many Requests",
"retryAfter": 30
}
With header: Retry-After: 30
7. Graceful Degradation
If Redis is unavailable:
- Fall back to in-memory rate limiting using a Map
- Apply 50% of normal limits
- Log a warning: "Redis unavailable, using in-memory rate limiting"
- Automatically switch back to Redis when it recovers
8. Exemptions
GET /health — exempt
GET /metrics — exempt
- Internal service-to-service calls (if applicable)
9. Testing
- Unit tests: sliding window calculation, limit enforcement, header generation
- Unit tests: adaptive limit increase after successful payments
- Unit tests: graceful degradation when Redis is down
- Integration tests: verify 429 returned when limit exceeded
- Load tests: 100 concurrent requests, verify rate limiting holds
- Test per-auth-type multipliers
[SEC] Sliding Window Rate Limiting with Adaptive Limits
Priority: High
Difficulty: Hard
Estimated Effort: 2-3 days
Relevant Packages:
OrbitStream_backend/Labels:
security,enhancement,priority:highRequirements
1. Sliding Window Implementation
Use Redis sorted sets for a true sliding window (not fixed window which allows 2x burst):
2. Per-Endpoint Limits
/auth/login/auth/verify/merchants/register/v1/checkout/sessions(POST)/v1/checkout/sessions/:id(GET)3. Per-Auth-Type Multipliers
4. Adaptive Limits
If a merchant has >10 successful payments in the last hour, increase their checkout creation limit by 50%. Check using a Redis counter
orbitstream:merchant_payments:{id}:{hour}.5. Response Headers
Every response includes:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 95X-RateLimit-Reset: 1640995200(Unix timestamp when window resets)6. 429 Response
{ "statusCode": 429, "message": "Rate limit exceeded", "error": "Too Many Requests", "retryAfter": 30 }With header:
Retry-After: 307. Graceful Degradation
If Redis is unavailable:
8. Exemptions
GET /health— exemptGET /metrics— exempt9. Testing