@perseidesjs/medusa-plugin-rate-limit
Website|Medusa
A simple rate-limitting plugin for Medusa.
Purpose
This plugin was mainly built to protect your MedusaJS application from abuse. This plugin allows you to easily manage request limits without stepping outside the familiar Medusa environment.
Why Rate Limiting Matters
- Shield Against Attacks: Prevent Denial of Service (DoS) attempts by capping the number of requests from a single source.
- Boost Security: Thwart brute force attacks and other automated threats by controlling request frequency.
- Easy Setup: Seamlessly integrate rate limiting into your existing Medusa configuration files.
Installation
1npm install @perseidesjs/medusa-plugin-rate-limit
Usage
This plugin uses Redis under the hood, this plugin will also work in a development environment thanks to the fake Redis instance created by Medusa, remember to use Redis in production, by just passing the Copy to clipboard
redis_url
option to the Copy to clipboardmedusa-config.js > projectConfig
object.
Plugin configuration
You need to add the plugin to your Medusa configuration before you can use the rate limitting service. To do this, import the plugin as follows:
12345const plugins = [`medusa-fulfillment-manual`,`medusa-payment-manual`,`@perseidesjs/medusa-plugin-rate-limit`,]
You can also override the default configuration by passing an object to the plugin as follows:
123456789101112const plugins = [`medusa-fulfillment-manual`,`medusa-payment-manual`,{resolve: `@perseidesjs/medusa-plugin-rate-limit`,/** @type {import('@perseidesjs/medusa-plugin-rate-limit').PluginOptions} */options: {limit: 5,window: 60,},},]
Default configuration
Option | Type | Default | Description |
---|---|---|---|
limit | Copy to clipboardNumber | Copy to clipboard5 | The number of requests allowed in the given time window |
window | Copy to clipboardNumber | Copy to clipboard60 | The time window in seconds |
How to use
If you want to start restricting certain routes, you can resolve the Copy to clipboard
RateLimitService
from the Medusa container, and then create middleware as shown below :
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748// src/middlewares/rate-limit.tsimport { type MedusaRequest, type MedusaResponse } from '@medusajs/medusa'import type { NextFunction } from 'express'import type { RateLimitService } from '@perseidesjs/medusa-plugin-rate-limit'/*** A simple rate limiter middleware based on the RateLimitService* @param limit {number} - Number of requests allowed per window* @param window {number} - Number of seconds to wait before allowing requests again* @returns*/export default async function rateLimit(req: MedusaRequest,res: MedusaResponse,next: NextFunction,) {try {// 1️⃣ We resolve the RateLimitService from the containerconst rateLimitService = req.scope.resolve<RateLimitService>('rateLimitService')// 2️⃣ We create a key for the current request based on the IP address for exampleconst key = req.ipconst rateLimitKey = `rate_limit:${key}`const allowed = await rateLimitService.limit(rateLimitKey)// 3️⃣ If the request is not allowed, we return a 429 status code and a JSON response with an error messageif (!allowed) {const retryAfter = await rateLimitService.ttl(rateLimitKey)res.set('Retry-After', String(retryAfter))res.status(429).json({ error: 'Too many requests, please try again later.' })return}// 4️⃣ Otherwise, we can continue, below I'm getting the remaining attempts for the current key for exampleconst remaining = await rateLimitService.getRemainingAttempts(rateLimitKey)res.set('X-RateLimit-Limit', String(rateLimitService.getOptions().limit))res.set('X-RateLimit-Remaining', String(remaining))next()} catch (error) {next(error)}}
And then use it in your Copy to clipboard
src/api/middlewares.ts
file as follows:123456789101112import { MiddlewaresConfig } from '@medusajs/medusa'import rateLimit from './middlewares/rate-limit'export const config: MiddlewaresConfig = {routes: [{// This will limit the number of requests to 5 per 60 seconds on the auth routematcher: '/store/auth',middlewares: [rateLimit],},],}
Default Middleware
We also provide a out of the box middleware that you can use immediately without needing to create your own. This middleware is exposed and can be used as follows:
123456789101112import { MiddlewaresConfig } from '@medusajs/medusa'import { rateLimitRoutes } from '@perseidesjs/medusa-plugin-rate-limit'export const config: MiddlewaresConfig = {routes: [{// This will limit the number of requests to 5 per 60 seconds on the auth route using the default middlewarematcher: '/store/auth',middlewares: [rateLimitRoutes],},],}
More information
You can find the Copy to clipboard
RateLimitService
class in the src/services/rate-limit.ts file.License
This project is licensed under the MIT License - see the LICENSE file for details