Basic Usage
Learn how to use the @perseidesjs/medusa-plugin-rate-limit plugin in your Medusa app
How to use
If you want to start restricting specific routes, you can import the RateLimit class from the plugin and then use it as follows:
import { defineMiddlewares } from "@medusajs/medusa"
import { RateLimit } from '@perseidesjs/medusa-plugin-rate-limit'
import { Modules } from "@medusajs/framework/utils"
export default defineMiddlewares({
routes: [
{
matcher: "/store/custom*",
middlewares: [
async (req: MedusaRequest, res: MedusaResponse, next: MedusaNextFunction) => {
const cacheService = req.scope.resolve(Modules.CACHE)
const rateLimit = new RateLimit({
cacheService,
options: {
limit: 50, // 50 requests per minute
window: 60
}
})
const ip = req.socket.remoteAddress as string
// đĒ This is where the magic happens
const { success } = await rateLimit.limit(ip)
if (!success) {
res.status(429).send('Too many requests, please try again later.')
return
}
next()
}
],
},
],
})req.socket.remoteAddress for the client IP. Avoid using x-forwarded-for directly as it can be spoofed. If you need proxy support, use the built-in ipRateLimit middleware with trustProxy instead.The idea is simple: limit the number of requests by the identifier/key of your choice. This is useful if you want to protect based on some business logic aspects, for example by basing it on a license plate in the context of a car website or by user id, you are free to manage this as you wish.
// âšī¸ A few examples in action...
// For example by header
await rateLimit.limit(req.headers['x-plate'])
// By user id
await rateLimit.limit(req.auth_context.actor_id)
// Or by a static value that will be global to all users
await rateLimit.limit('global')Built-in IP Rate Limiting
For the common use case of IP-based rate limiting, V3 includes a ready-to-use ipRateLimit middleware:
import { defineMiddlewares } from "@medusajs/medusa"
import { ipRateLimit } from '@perseidesjs/medusa-plugin-rate-limit'
export default defineMiddlewares({
routes: [
{
matcher: "/store/auth*",
middlewares: [ipRateLimit({
limit: 10,
window: 60
})],
},
],
})The ipRateLimit middleware automatically:
- Extracts the client IP address
- Sets appropriate rate limit headers (
X-RateLimit-Limit,X-RateLimit-Remaining) - Returns a 429 status when the limit is exceeded
Extracting the client IP
By default, ipRateLimit uses req.socket.remoteAddress (the direct connection IP). This prevents attackers from bypassing rate limiting by spoofing the X-Forwarded-For header.
If your server is behind a reverse proxy (nginx, Cloudflare, etc.), enable trustProxy:
ipRateLimit({
limit: 10,
window: 60,
trustProxy: 1 // Number of trusted proxy hops
})trustProxy value | Behavior |
|---|---|
false (default) | Uses direct connection IP. Ignores X-Forwarded-For. |
true | Uses leftmost IP from X-Forwarded-For. Only use if your proxy overwrites the header. |
number | Number of trusted proxy hops. Extracts IP from the right side of the header, preventing spoofing. |
Example with trustProxy: 1:
X-Forwarded-For: spoofed-ip, real-client-ip
â uses this (rightmost)trustProxy if your server is behind a trusted reverse proxy. Enabling it without a proxy allows clients to spoof their IP and bypass rate limiting.