Rate Limiter

The Rate Limiter component protects your application from abuse, denial-of-service (DoS) attacks, and brute-force attempts by limiting the frequency of incoming requests from a single IP address.

Built on top of express-rate-limit, it provides a standardized way to apply rate limits globally or to specific sensitive routes.

Installation Guide

This component requires additional Servercn components.

👉 You do not need to install any Servercn components manually. Running this component installer will automatically install all required components. Manual installation is optional and only recommended if you prefer fine-grained components control

npx servercn-cli add rate-limiter

Configuration Options

The rate limiter can be customized to fit your application's needs:

  • windowMs: The timeframe for which requests are checked (in milliseconds).
  • max: The maximum number of connections to allow during the windowMs before returning a 429 error.
  • standardHeaders: Enables the RateLimit-* headers in the response.
  • handler: A custom function to execute when the limit is reached. In Servercn, we use it to forward the error to our global error handler.

Basic Implementation

MVC: src/middlewares/rate-limiter.ts

Modular: src/shared/middlewares/rate-limiter.ts

import { rateLimit } from "express-rate-limit";
import { STATUS_CODES } from "../constants/status-codes";
import { ApiError } from "../utils/api-error";
 
export const rateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per window
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  legacyHeaders: false, // Disable the `X-RateLimit-*` headers
  message: {
    success: false,
    message:
      "Too many requests from this IP, please try again after 15 minutes",
    status: 429
  },
  handler: (req, res, next, options) => {
    next(new ApiError(STATUS_CODES.TOO_MANY_REQUESTS, options.message.message));
  }
});
 
/**
 * Stricter rate limiter for sensitive routes (e.g., auth, login)
 */
export const authRateLimiter = rateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour
  max: 5, // Limit each IP to 5 failed attempts per hour
  handler: (req, res, next, options) => {
    next(
      ApiError.tooManyRequests(
        "Too many login attempts, please try again after an hour"
      )
    );
  }
});
 
/**
 * Rate limiter for login route
 */
export const signinRateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: {
    success: false,
    message: "Too many login attempts, please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});
 
/**
 * Rate limiter for registration route
 */
export const signupRateLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: {
    success: false,
    message: "Too many registration attempts, please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});
 
export const otpRequestLimiter = rateLimit({
  windowMs: 10 * 60 * 1000,
  max: 6,
  message: {
    success: false,
    message: "Too many OTP requests. Please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});
 
export const otpVerificationLimiter = rateLimit({
  windowMs: 10 * 60 * 1000,
  max: 6,
  message: {
    success: false,
    message: "Too many OTP verification attempts. Please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});
 
export const resetPasswordLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 6,
  message: {
    success: false,
    message: "Too many password reset attempts, please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});
 
export const deleteAccountLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: {
    success: false,
    message: "Too many account deletion attempts, please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});
 
export const changePasswordLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: {
    success: false,
    message: "Too many password change attempts, please try again later.",
    statusCode: 429
  },
  standardHeaders: true,
  legacyHeaders: false
});

Usage Guide

Apply the rate limiter globally in your main app.ts file to protect all routes by default.

src/app.ts
import express from "express";
import { rateLimiter } from "./middlewares/rate-limiter";
 
const app = express();
 
// Apply the rate limiting middleware to all requests
app.use(rateLimiter);
 
// ... rest of your app configuration

For sensitive routes like login, password reset, or expensive search operations, you should apply stricter limits.

src/routes/auth.routes.ts
import { Router } from "express";
import { authRateLimiter } from "../middlewares/rate-limiter";
 
const router = Router();
 
// Only apply to the login route
router.post("/login", authRateLimiter, (req, res) => {
  // Login logic...
});
 
export default router;

File & Folder Structure

ServerCN

Select a file to view its contents

Installation

npx servercn-cli add rate-limiter