Rate Limiting & Redis
Distributed, role-aware rate limiting using rate-limiter-flexible with ioredis, including per-endpoint strategies and Cloudflare-aware IP extraction.
Rate Limiting & Redis
The SLMS uses a distributed, enterprise-grade rate limiting system powered by rate-limiter-flexible with ioredis as the backing store. Each endpoint category has its own tuned algorithm and threshold.
Architecture
Incoming Request
│
▼
┌─────────────────────┐
│ getClientIp(req) │ ← CF-Connecting-IP → X-Forwarded-For → req.ip
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Rate Limiter │ ← Redis (production) / Memory (development fallback)
│ (rate-limiter- │
│ flexible) │
└─────────────────────┘
│
├── Allow → Set RateLimit-* headers → next()
└── Reject → 429 + Retry-After headerFiles
| File | Purpose |
|---|---|
middleware/rateLimiter.js | All rate limiter definitions and middleware exports |
utils/redisClient.js | Redis connection management with environment-aware fallback |
utils/getClientIp.js | Cloudflare-aware IP extraction helper |
Redis Connection Strategy
// utils/redisClient.js
if (process.env.REDIS_URL) {
// Connect to Redis
} else if (process.env.NODE_ENV === 'production') {
// FAIL — Redis is mandatory in production
throw new Error('REDIS_URL is required in production');
} else {
// Development fallback: in-memory rate limiting
redisClient = null;
}| Environment | Behavior |
|---|---|
| Production | Redis is mandatory. Application crashes on startup if REDIS_URL is missing. |
| Development | Redis is optional. Falls back to in-memory RateLimiterMemory. |
Client: ioredis (chosen over redis for better reconnection, cluster support, and Sentinel compatibility).
Rate Limiter Definitions
All limiters use Redis Lua scripts for atomic operations. Keys are prefixed with rl: (e.g., rl:login:email:user@example.com).
Authentication Endpoints
| Limiter | Algorithm | Limit | Duration | Key | Notes |
|---|---|---|---|---|---|
loginEmailLimiter | Sliding Window + Progressive Delay | 5 req | 15 min | Delays escalate: 1s → 2s → 4s → 8s → reject at 10th | |
loginIpLimiter | Fixed Window | 20 req | 15 min | IP | Catches credential stuffing from single IPs |
registerLimiter | Fixed Window | 3 req | 1 hour | IP | Prevents mass account creation |
forgotPasswordLimiter | Fixed Window | 3 req | 1 hour | Prevents email enumeration | |
refreshLimiter | Token Bucket | 30 req | 1 min | Token | Rate-limits token refresh abuse |
API Endpoints (Role-Aware)
The globalApiLimiter applies different thresholds based on the authenticated user's role:
| Role | Limit | Duration |
|---|---|---|
| Anonymous | 60 req | 1 min |
| Student | 100 req | 1 min |
| Faculty | 150 req | 1 min |
| Librarian | 200 req | 1 min |
| Admin | 300 req | 1 min |
Specialized Endpoints
| Limiter | Limit | Duration | Key |
|---|---|---|---|
searchLimiter (simple) | 100 req | 1 min | User ID / IP |
searchLimiter (advanced) | 40 req | 1 min | User ID / IP |
uploadLimiter | 10 req | 1 min | User ID / IP |
bulkOpsLimiter | 5 req | 1 hour | User ID / IP |
Response Headers
Every rate-limited response includes standard RateLimit-* headers:
RateLimit-Limit: 100
RateLimit-Remaining: 87
RateLimit-Reset: 1719946500On rejection, a Retry-After header (in seconds) is also set.
IP Extraction (Cloudflare-Aware)
// utils/getClientIp.js
const getClientIp = (req) => {
return req.headers['cf-connecting-ip'] // Cloudflare
|| req.headers['x-forwarded-for']?.split(',')[0].trim()
|| req.ip
|| req.connection?.remoteAddress
|| 'unknown';
};Priority order:
CF-Connecting-IP(Cloudflare's true client IP header)X-Forwarded-For(first entry from proxy chain)req.ip(Express, respectstrust proxysetting)req.connection.remoteAddress(direct connection fallback)
Progressive Delay (Login)
The login email limiter implements progressive delay rather than immediate rejection:
Attempt 1-5: Allowed instantly
Attempt 6: 1 second delay before responding
Attempt 7: 2 second delay
Attempt 8: 4 second delay
Attempt 9: 8 second delay
Attempt 10+: Rejected with 429 + Retry-AfterThis slows down automated attacks without immediately alerting attackers that rate limiting is active.
Authentication & Security
Enterprise-grade JWT + Refresh Token authentication with Argon2id hashing, per-session tracking, RBAC, and brute-force protection.
Error Handling & API Response Format
Standardized enterprise error handling with machine-readable error codes, validation error mapping, and consistent API response contracts.