Browse Source

RHL-003-feat(auth): implement login endpoint with request validation and session creation

Code_Uwe 1 week ago
parent
commit
576f6488b1
1 changed files with 76 additions and 0 deletions
  1. 76 0
      app/api/auth/login/route.js

+ 76 - 0
app/api/auth/login/route.js

@@ -0,0 +1,76 @@
+import bcrypt from "bcryptjs";
+import User from "@/models/user";
+import dbConnect from "@/lib/db";
+import { createSession } from "@/lib/auth/session";
+
+/**
+ * POST /api/auth/login
+ *
+ * Body (JSON):
+ * {
+ *   "username": "example.user",
+ *   "password": "plain-text-password"
+ * }
+ */
+export async function POST(request) {
+	try {
+		let body;
+
+		try {
+			body = await request.json();
+		} catch {
+			return jsonResponse({ error: "Invalid request body" }, 400);
+		}
+
+		if (!body || typeof body !== "object") {
+			return jsonResponse({ error: "Invalid request body" }, 400);
+		}
+
+		const { username, password } = body;
+
+		if (
+			typeof username !== "string" ||
+			typeof password !== "string" ||
+			!username.trim() ||
+			!password.trim()
+		) {
+			return jsonResponse({ error: "Missing username or password" }, 400);
+		}
+
+		const normalizedUsername = username.trim().toLowerCase();
+
+		await dbConnect();
+
+		const user = await User.findOne({ username: normalizedUsername }).exec();
+
+		if (!user) {
+			return jsonResponse({ error: "Invalid credentials" }, 401);
+		}
+
+		const passwordMatches = await bcrypt.compare(password, user.passwordHash);
+
+		if (!passwordMatches) {
+			return jsonResponse({ error: "Invalid credentials" }, 401);
+		}
+
+		await createSession({
+			userId: user._id.toString(),
+			role: user.role,
+			branchId: user.branchId ?? null,
+		});
+
+		return jsonResponse({ ok: true }, 200);
+	} catch (error) {
+		console.error("Login error:", error);
+		return jsonResponse({ error: "Internal server error" }, 500);
+	}
+}
+
+function jsonResponse(data, status = 200) {
+	return new Response(JSON.stringify(data), {
+		status,
+		headers: {
+			"Content-Type": "application/json",
+		},
+	});
+}