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
26 changes: 26 additions & 0 deletions apps/web/src/app/api/auth/login/__tests__/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 13 additions & 2 deletions apps/web/src/app/api/auth/login/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
}

Expand Down
Loading