Skip to content

Commit b85ffb9

Browse files
API rate limit middleware integration
1 parent 315048e commit b85ffb9

File tree

5 files changed

+124
-5
lines changed

5 files changed

+124
-5
lines changed

package-lock.json

Lines changed: 20 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"dotenv": "^16.0.3",
7373
"express": "^4.18.2",
7474
"express-mongo-sanitize": "^2.2.0",
75+
"express-rate-limit": "^6.7.0",
7576
"express-session": "^1.17.3",
7677
"firebase-admin": "^11.5.0",
7778
"helmet": "^6.0.1",

src/api/v1/auth/auth.route.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import express from 'express';
22
import passport from '../../../config/passport.config';
3+
import {
4+
recoverPasswordApiLimiter,
5+
resetPasswordApiLimiter,
6+
} from '../../../middlewares/apiRateLimit.middleware';
37
import catchAsyncHandler from '../../../middlewares/catchAsyncHandler.middleware';
48
import {requireAuthenticationMiddleware} from '../../../middlewares/requireAuthentication.middleware';
59

@@ -18,8 +22,16 @@ const authRouter = express.Router();
1822
authRouter.post('/signup', catchAsyncHandler(signup));
1923
authRouter.post('/login', catchAsyncHandler(login));
2024
authRouter.post('/logout', catchAsyncHandler(logout));
21-
authRouter.post('/recover-password', catchAsyncHandler(recoverPassword));
22-
authRouter.post('/reset-password', catchAsyncHandler(resetPassword));
25+
authRouter.post(
26+
'/recover-password',
27+
recoverPasswordApiLimiter,
28+
catchAsyncHandler(recoverPassword)
29+
);
30+
authRouter.post(
31+
'/reset-password',
32+
resetPasswordApiLimiter,
33+
catchAsyncHandler(resetPassword)
34+
);
2335
authRouter.get(
2436
'/me',
2537
requireAuthenticationMiddleware,

src/api/v1/index.route.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
import express, {Response} from 'express';
22
import _ from 'lodash';
33
import {ICustomExpressRequest} from '../../middlewares/currentUser.middleware';
4+
45
import appRouter from './app/app.route';
6+
import authRouter from './auth/auth.route';
7+
58
import swaggerRouter from './swagger/swagger.route';
69
import typedocRouter from './typedoc/typedoc.route';
7-
import authRouter from './auth/auth.route';
10+
11+
import {
12+
apiV1RateLimiter,
13+
devlopmentApiLimiter,
14+
} from '../../middlewares/apiRateLimit.middleware';
815

916
const apiV1Router = express.Router();
1017

@@ -38,11 +45,13 @@ const devRoutes = [
3845
];
3946

4047
_.forEach(defaultRoutes, route => {
48+
apiV1Router.use(apiV1RateLimiter);
4149
apiV1Router.use(route.path, route.route);
4250
});
4351

4452
if (process.env.NODE_ENV === 'development') {
4553
_.forEach(devRoutes, route => {
54+
apiV1Router.use(devlopmentApiLimiter);
4655
apiV1Router.use(route.path, route.route);
4756
});
4857
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {Response} from 'express';
2+
import rateLimit from 'express-rate-limit';
3+
import {ICustomExpressRequest} from './currentUser.middleware';
4+
5+
/**
6+
* Rate limiter for api v1
7+
* @see https://www.npmjs.com/package/express-rate-limit
8+
* @description 1000 requests per 1 minute for production
9+
*/
10+
const apiV1RateLimiter = rateLimit({
11+
windowMs: 1 * 60 * 1000, // 1 minute
12+
max: 200, // Limit each IP to 200 requests per `window` (here, per 1 minute)
13+
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
14+
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
15+
message: async (req: ICustomExpressRequest, res: Response) => {
16+
return res.status(429).json({
17+
status: 'error',
18+
message: 'You have exceeded the 100 requests in 1 minute limit!',
19+
});
20+
},
21+
});
22+
23+
/**
24+
* Rate limiter for development route as typedoc and swagger
25+
* @description 1000 requests per 1 hour for development
26+
*/
27+
const devlopmentApiLimiter = rateLimit({
28+
windowMs: 60 * 60 * 1000, // 59 minute
29+
max: 1000, // Limit each IP to 1000 requests per `window` (here, per 1 hour)
30+
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
31+
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
32+
message: async (req: ICustomExpressRequest, res: Response) => {
33+
return res.status(429).json({
34+
status: 'error',
35+
message: 'Too many requests, please try again in 10 minutes.',
36+
});
37+
},
38+
});
39+
40+
/**
41+
* Rate limiter for recover password
42+
*/
43+
const recoverPasswordApiLimiter = rateLimit({
44+
windowMs: 1 * 60 * 1000, // 5 minute
45+
max: 1, // Limit each IP to 1020 requests per `window` (here, per 1 minute)
46+
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
47+
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
48+
message: async (req: ICustomExpressRequest, res: Response) => {
49+
return res.status(429).json({
50+
status: 'error',
51+
message:
52+
'Too many requests to recover password, please try again in 1 minute.',
53+
});
54+
},
55+
});
56+
57+
/**
58+
* Rate limiter for reset password
59+
*/
60+
const resetPasswordApiLimiter = rateLimit({
61+
windowMs: 1 * 60 * 1000, // 1 minute
62+
max: 10, // Limit each IP to 10 requests per `window` (here, per 1 minute)
63+
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
64+
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
65+
message: async (req: ICustomExpressRequest, res: Response) => {
66+
return res.status(429).json({
67+
status: 'error',
68+
message:
69+
'Too many requests to reset password, please try again in 1 minute.',
70+
});
71+
},
72+
});
73+
74+
export {
75+
apiV1RateLimiter,
76+
devlopmentApiLimiter,
77+
recoverPasswordApiLimiter,
78+
resetPasswordApiLimiter,
79+
};

0 commit comments

Comments
 (0)