diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts index c5b6a86f5..d39e8bd6a 100644 --- a/src/app/api/auth/[...nextauth]/route.ts +++ b/src/app/api/auth/[...nextauth]/route.ts @@ -5,41 +5,65 @@ import { NextRequest, NextResponse } from "next/server"; const handler = NextAuth(authOptions); const rateLimitMap = new Map(); + const RATE_LIMIT_MAX = 10; const RATE_LIMIT_WINDOW_MS = 60 * 1000; +type AuthRouteContext = { + params: Promise<{ nextauth: string[] }>; +}; + function getClientIP(req: NextRequest): string { return ( - req.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? - req.headers.get("x-real-ip") ?? + req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || + req.headers.get("x-real-ip") || "unknown" ); } function isRateLimited(ip: string): boolean { const now = Date.now(); + const entry = rateLimitMap.get(ip); + if (!entry || now > entry.resetAt) { - rateLimitMap.set(ip, { count: 1, resetAt: now + RATE_LIMIT_WINDOW_MS }); + rateLimitMap.set(ip, { + count: 1, + resetAt: now + RATE_LIMIT_WINDOW_MS, + }); + return false; } - if (entry.count >= RATE_LIMIT_MAX) return true; - entry.count++; + + if (entry.count >= RATE_LIMIT_MAX) { + return true; + } + + entry.count += 1; return false; } -export async function GET(req: NextRequest, ctx: { params: Promise<{ nextauth: string[] }> }) { +export async function GET(req: NextRequest, ctx: AuthRouteContext) { const params = await ctx.params; return handler(req, { params }); } -export async function POST(req: NextRequest, ctx: { params: Promise<{ nextauth: string[] }> }) { - const ip = getClientIP(req); - if (isRateLimited(ip)) { - return NextResponse.redirect( - new URL("/auth/signin?error=RateLimitError", req.url) - ); - } +export async function POST(req: NextRequest, ctx: AuthRouteContext) { const params = await ctx.params; + const action = params.nextauth?.[0]; + + const shouldRateLimit = action === "signin" || action === "callback"; + + if (shouldRateLimit) { + const ip = getClientIP(req); + + if (isRateLimited(ip)) { + return NextResponse.redirect( + new URL("/auth/signin?error=RateLimitError", req.url), + { status: 303 } + ); + } + } + return handler(req, { params }); -} \ No newline at end of file +}