Skip to Content
Middleware (guards)rate-limit.middleware.ts

rate-limit.middleware.ts

Cuts off API abuse — brute-force logins, scraping, expensive admin POSTs, runaway worker calls. Policies live in MongoDB and can be edited live from the admin app without redeploying.

The full design (policies, algorithms, stores, admin UI, default seeds, kill switches) is documented in API rate limiting. This page describes just the middleware glue in src/middleware/rate-limit.middleware.ts.

Where it runs

Mounted globally after CORS and request-id, before any route:

app.use('*', cors(...)) app.use('*', requestIdMiddleware) app.use('*', rateLimitMiddleware)

What it does on every request

  1. Pulls the cached RateLimitConfig (singleton, ~30s in-process cache).
  2. Resolves the identity:
    • prefers c.get('userId') (from authMiddleware if it ran),
    • else decodes a Bearer JWT in Authorization without running full auth,
    • else falls back to client IP (CF-Connecting-IP → last X-Forwarded-For'unknown'),
    • flags super admin (cached 30s) and internal worker (x-internal-key timing-safe equal to NOTIFICATION_WORKER_KEY).
  3. Calls the policy engine to score the request against every matching policy.
  4. Sets RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset headers.
  5. Decides one of:
    • Allowed (most cases) — calls next(). With probability RATE_LIMIT_EVENT_SAMPLE_RATE (default 1%), writes a sampled allowed event.
    • Shadow violationnext() runs, but writes a shadow_violation event so dashboards show what would have blocked.
    • Blocked — returns 429 with Retry-After, a RATE_LIMITED code, the offending policy id, and requestId. Writes a blocked event.

Fail-open

If anything throws (DB outage, malformed config), the middleware logs RATE_LIMITER_DEGRADED via logServerError(...) and still calls next(). The product would rather serve traffic than be taken down by its own limiter.

Factory for tests

createRateLimitMiddleware({ store, loadConfig, now, eventSampleRate, recordEvent }) lets unit tests swap the store (memory vs mongo), the config loader (snapshot in memory), and the clock. Tests live in src/__tests__/rate-limit-*.test.ts.

  • API rate limiting — admin UI, env vars, default policies
  • Admin routes/api/v1/admin/rate-limits editor
  • services/rate-limit/ — algorithms, stores, policy engine, config cache
  • models/rate-limit-*.model.tsRateLimitConfig, RateLimitCounter, RateLimitEvent, RateLimitRollup, RateLimitAudit
Last updated on