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
npxservercn-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
Global Rate Limiting
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 requestsapp.use(rateLimiter);// ... rest of your app configuration
Route-Specific Rate Limiting
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 routerouter.post("/login", authRateLimiter, (req, res) => { // Login logic...});export default router;