diff --git a/backend/src/server/config/rateLimiter.ts b/backend/src/server/config/rateLimiter.ts index 6c92de62c..0f6903773 100644 --- a/backend/src/server/config/rateLimiter.ts +++ b/backend/src/server/config/rateLimiter.ts @@ -52,6 +52,15 @@ export const inviteUserRateLimit: RateLimitOptions = { keyGenerator: (req) => req.realIp }; +export const mfaRateLimit: RateLimitOptions = { + timeWindow: 60 * 1000, + max: 20, + keyGenerator: (req) => { + // fallback to IP to avoid global rate limiting when authorization is set to empty + return req.headers.authorization?.split(" ")[1] || req.realIp; + } +}; + export const creationLimit: RateLimitOptions = { // identity, project, org timeWindow: 60 * 1000, diff --git a/backend/src/server/routes/v2/mfa-router.ts b/backend/src/server/routes/v2/mfa-router.ts index 973804c7c..1c685866d 100644 --- a/backend/src/server/routes/v2/mfa-router.ts +++ b/backend/src/server/routes/v2/mfa-router.ts @@ -2,7 +2,7 @@ import jwt from "jsonwebtoken"; import { z } from "zod"; import { getConfig } from "@app/lib/config/env"; -import { writeLimit } from "@app/server/config/rateLimiter"; +import { mfaRateLimit } from "@app/server/config/rateLimiter"; import { AuthModeMfaJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type"; export const registerMfaRouter = async (server: FastifyZodProvider) => { @@ -34,7 +34,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { method: "POST", url: "/mfa/send", config: { - rateLimit: writeLimit + rateLimit: mfaRateLimit }, schema: { response: { @@ -53,7 +53,7 @@ export const registerMfaRouter = async (server: FastifyZodProvider) => { url: "/mfa/verify", method: "POST", config: { - rateLimit: writeLimit + rateLimit: mfaRateLimit }, schema: { body: z.object({