A simple rate-limitting plugin for Medusa.
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.
- 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.
npm install @perseidesjs/medusa-plugin-rate-limit
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 redis_url
option to the medusa-config.js > projectConfig
object.
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:
const 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:
const 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,
},
},
]
Option | Type | Default | Description |
---|---|---|---|
limit | Number |
5 |
The number of requests allowed in the given time window |
window | Number |
60 |
The time window in seconds |
If you want to start restricting certain routes, you can resolve the RateLimitService
from the Medusa container, and then create middleware as shown below :
// src/middlewares/rate-limit.ts
import { 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 container
const rateLimitService = req.scope.resolve<RateLimitService>('rateLimitService')
// 2️⃣ We create a key for the current request based on the IP address for example
const key = req.ip
const 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 message
if (!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 example
const 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 src/api/middlewares.ts
file as follows:
import { 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 route
matcher: '/store/auth',
middlewares: [rateLimit],
},
],
}
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:
import { 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 middleware
matcher: '/store/auth',
middlewares: [rateLimitRoutes],
},
],
}
You can find the RateLimitService
class in the src/services/rate-limit.ts file.
This project is licensed under the MIT License - see the LICENSE file for details