diff --git a/apps/web/src/app/api/auth/login/__tests__/route.test.ts b/apps/web/src/app/api/auth/login/__tests__/route.test.ts index a3e2f44..575f711 100644 --- a/apps/web/src/app/api/auth/login/__tests__/route.test.ts +++ b/apps/web/src/app/api/auth/login/__tests__/route.test.ts @@ -52,6 +52,14 @@ function makeRequest(body: unknown) { }) as unknown as import("next/server").NextRequest; } +function makeRawRequest(body: string) { + return new Request("http://localhost/api/auth/login", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body, + }) as unknown as import("next/server").NextRequest; +} + describe("POST /api/auth/login", () => { beforeEach(() => { vi.clearAllMocks(); @@ -105,6 +113,24 @@ describe("POST /api/auth/login", () => { expect(body.error).toContain("Email and password are required"); }); + it("rejects malformed JSON without calling Supabase", async () => { + const res = await POST(makeRawRequest("{")); + const body = await res.json(); + + expect(res.status).toBe(400); + expect(body.error).toBe("Invalid JSON body"); + expect(mockSignIn).not.toHaveBeenCalled(); + }); + + it("rejects non-object JSON without calling Supabase", async () => { + const res = await POST(makeRequest(null)); + const body = await res.json(); + + expect(res.status).toBe(400); + expect(body.error).toBe("Invalid JSON body"); + expect(mockSignIn).not.toHaveBeenCalled(); + }); + it("response shape matches contract", async () => { const req = makeRequest({ email: "test@example.com", password: "securePass1!" }); const res = await POST(req); diff --git a/apps/web/src/app/api/auth/login/route.ts b/apps/web/src/app/api/auth/login/route.ts index b9f9385..105eecb 100644 --- a/apps/web/src/app/api/auth/login/route.ts +++ b/apps/web/src/app/api/auth/login/route.ts @@ -3,9 +3,20 @@ import { getSupabaseClient, getSupabaseAdmin } from "@/lib/supabase"; export async function POST(req: NextRequest) { try { - const { email, password } = await req.json(); + let body: { email?: unknown; password?: unknown }; + try { + const parsed: unknown = await req.json(); + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) { + return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); + } + body = parsed as { email?: unknown; password?: unknown }; + } catch { + return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 }); + } + + const { email, password } = body; - if (!email || !password) { + if (typeof email !== "string" || typeof password !== "string" || !email || !password) { return NextResponse.json({ error: "Email and password are required" }, { status: 400 }); }