Rate Limiting

Redis-Backed Rate Limits and Tighter Auth-Route Guards

Rate Limiting

koa-ratelimit counts requests per identifier in Redis and returns 429 Too Many Requests with standard headers when the limit is exceeded. Auth routes deserve tighter thresholds than general API routes.

3 min read Level 2/5 #koa#rate-limiting#security
What you'll learn
  • Configure koa-ratelimit with a Redis store
  • Apply a stricter rate limit specifically to login and registration routes
  • Return 429 with standard RateLimit-* headers

Rate limiting is a critical control against brute-force login attacks, credential stuffing, and API abuse. Without it, an attacker can try millions of password combinations against your /login endpoint.

Installation

npm install koa-ratelimit ioredis

Basic Setup

import Koa from "koa";
import ratelimit from "koa-ratelimit";
import Redis from "ioredis";

const app = new Koa();
const redis = new Redis(process.env.REDIS_URL);

// Global limit: 300 requests per minute per IP.
app.use(
  ratelimit({
    driver: "redis",
    db: redis,
    duration: 60_000,      // window in ms
    max: 300,              // requests per window
    id: (ctx) => ctx.ip,  // key by IP
    headers: {
      remaining: "RateLimit-Remaining",
      reset: "RateLimit-Reset",
      total: "RateLimit-Limit",
    },
    errorMessage: "Too many requests — please slow down.",
    disableHeader: false,
  })
);

Tighter Limits on Auth Routes

Apply a separate, stricter limiter as route-level middleware on auth endpoints.

const authLimiter = ratelimit({
  driver: "redis",
  db: redis,
  duration: 15 * 60_000, // 15-minute window
  max: 10,               // only 10 attempts per window
  id: (ctx) => `auth:${ctx.ip}`,
  errorMessage: "Too many login attempts — try again in 15 minutes.",
});

router.post("/auth/login", authLimiter, async (ctx) => {
  // login logic
});

router.post("/auth/register", authLimiter, async (ctx) => {
  // registration logic
});

Response Headers

koa-ratelimit sets standard headers on every response:

HeaderMeaning
RateLimit-LimitMaximum requests allowed in the window
RateLimit-RemainingRequests left in the current window
RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds until reset (on 429 responses)

These headers let clients back off gracefully rather than hammering the server.

Keying Strategies

The id function determines how requests are grouped. Common strategies:

// By IP (default — good for anonymous routes)
id: (ctx) => ctx.ip,

// By authenticated user ID (prevents shared-IP false positives)
id: (ctx) => ctx.state.user?.sub ?? ctx.ip,

// By IP + route (isolates per-endpoint budgets)
id: (ctx) => `${ctx.ip}:${ctx.path}`,

Up Next

Validate and sanitize all incoming input to prevent injection attacks and XSS before data reaches your business logic.

Input Validation & Sanitization →