Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 30 additions & 10 deletions backend/routes/authRoutes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express';
import rateLimit from 'express-rate-limit';
import rateLimit, { ipKeyGenerator } from 'express-rate-limit';
import {
signup,
login,
Expand All @@ -16,21 +16,41 @@ import { authMiddleware } from '../middlewares/authMiddleware.js';

const router = express.Router();

// ─── Rate limiter for all 2FA endpoints ───────────────────────────────────────
// Max 5 attempts per 15 minutes β€” prevents brute-force on TOTP codes
const twoFALimiter = rateLimit({
const RATE_LIMIT_MESSAGE = { message: 'Too many attempts, please try again later' };

const baseAuthLimitOptions = {
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5,
standardHeaders: true,
legacyHeaders: false,
message: { message: 'Too many attempts, please try again later' },
message: RATE_LIMIT_MESSAGE,
};

const normalizeEmail = (req) => String(req.body?.email ?? '').trim().toLowerCase();

// Max 10 auth attempts per IP per 15 minutes β€” caps credential stuffing / signup spam
const authByIpLimiter = rateLimit({
...baseAuthLimitOptions,
max: 10,
keyGenerator: (req) => ipKeyGenerator(req.ip),
});

// Max 5 attempts per email per 15 minutes β€” protects individual accounts from brute-force
const authByEmailLimiter = rateLimit({
...baseAuthLimitOptions,
max: 5,
keyGenerator: (req) => normalizeEmail(req) || ipKeyGenerator(req.ip),
});

// Max 5 attempts per 15 minutes β€” prevents brute-force on TOTP codes
const twoFALimiter = rateLimit({
...baseAuthLimitOptions,
max: 5,
});
// ──────────────────────────────────────────────────────────────────────────────

// Public routes
router.post('/signup', signup);
router.post('/login', login);
router.post('/google-login', googleLogin);
router.post('/signup', authByIpLimiter, authByEmailLimiter, signup);
router.post('/login', authByIpLimiter, authByEmailLimiter, login);
router.post('/google-login', authByIpLimiter, googleLogin);

// 2FA login completion (rate limited β€” protects TOTP brute-force)
router.post('/login-2fa', twoFALimiter, loginWith2FA);
Expand Down
2 changes: 2 additions & 0 deletions backend/src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const PORT = process.env.PORT;
// Initialize express
const app = express();

// Required for correct req.ip behind Render / reverse proxies (used by rate limiting)
app.set('trust proxy', 1);

app.use(
cors({
Expand Down