Fixed the login again?

This commit is contained in:
2026-06-26 22:30:54 +02:00
parent cd37d5a987
commit 39fb39db12
5 changed files with 51 additions and 58 deletions
+29 -21
View File
@@ -1,4 +1,4 @@
import { NextRequest, NextResponse } from "next/server"
import { NextRequest } from "next/server"
import {
comparePassword,
getUserByEmail,
@@ -13,6 +13,13 @@ import {
SESSION_COOKIE,
} from "@/lib/auth"
function jsonResponse(data: unknown, status: number) {
return new Response(JSON.stringify(data), {
status,
headers: { "Content-Type": "application/json" },
})
}
export async function POST(request: NextRequest) {
try {
const { email, username, password } = await request.json()
@@ -20,16 +27,16 @@ export async function POST(request: NextRequest) {
const credential = email || username
if (!credential || !password) {
return NextResponse.json(
return jsonResponse(
{ error: "Email/Username and password are required." },
{ status: 400 }
400
)
}
if (credential.trim().length === 0 || password.trim().length === 0) {
return NextResponse.json(
return jsonResponse(
{ error: "Credentials cannot be empty." },
{ status: 400 }
400
)
}
@@ -59,9 +66,9 @@ export async function POST(request: NextRequest) {
false,
"User not found"
)
return NextResponse.json(
return jsonResponse(
{ error: "Invalid email/username or password." },
{ status: 401 }
401
)
}
@@ -75,9 +82,9 @@ export async function POST(request: NextRequest) {
false,
lockStatus.reason
)
return NextResponse.json(
return jsonResponse(
{ error: lockStatus.reason },
{ status: 423 }
423
)
}
@@ -92,9 +99,9 @@ export async function POST(request: NextRequest) {
false,
"Invalid password"
)
return NextResponse.json(
return jsonResponse(
{ error: "Invalid email/username or password." },
{ status: 401 }
401
)
}
@@ -112,19 +119,20 @@ export async function POST(request: NextRequest) {
const user = mapDbUserToSessionUser(dbUser)
const response = NextResponse.json({ user }, { status: 200 })
response.cookies.set(SESSION_COOKIE, token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
path: "/",
const cookieStr = `${SESSION_COOKIE}=${token}; HttpOnly; SameSite=Strict; Path=/; Max-Age=86400${process.env.NODE_ENV === "production" ? "; Secure" : ""}`
return new Response(JSON.stringify({ user }), {
status: 200,
headers: {
"Content-Type": "application/json",
"Set-Cookie": cookieStr,
},
})
return response
} catch (error) {
console.error("Login error:", error)
return NextResponse.json(
{ error: "Authentication service unavailable." },
{ status: 503 }
return new Response(
JSON.stringify({ error: "Authentication service unavailable." }),
{ status: 503, headers: { "Content-Type": "application/json" } }
)
}
}
+9 -12
View File
@@ -1,22 +1,19 @@
import { NextResponse } from "next/server"
import { SESSION_COOKIE } from "@/lib/auth"
export async function POST() {
try {
const response = NextResponse.json({ success: true }, { status: 200 })
response.cookies.set(SESSION_COOKIE, "", {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
path: "/",
maxAge: 0,
return new Response(JSON.stringify({ success: true }), {
status: 200,
headers: {
"Content-Type": "application/json",
"Set-Cookie": `${SESSION_COOKIE}=; HttpOnly; SameSite=Strict; Path=/; Max-Age=0`,
},
})
return response
} catch (error) {
console.error("Logout error:", error)
return NextResponse.json(
{ error: "Logout failed." },
{ status: 500 }
return new Response(
JSON.stringify({ error: "Logout failed." }),
{ status: 500, headers: { "Content-Type": "application/json" } }
)
}
}
+1 -1
View File
@@ -62,7 +62,7 @@ export function Sidebar({ collapsed, onToggle, mobileOpen, onMobileClose }: Side
>
{/* Logo */}
<div className={cn("flex h-16 items-center border-b border-sidebar-border px-4", collapsed ? "justify-center" : "justify-between")}>
<Link href="/" className="flex items-center gap-3 overflow-hidden">
<Link href="/dashboard" className="flex items-center gap-3 overflow-hidden">
{collapsed ? (
<div className="bc-logo" style={{padding: "8px 3px", fontSize: "16px"}}>B<span className="accent">C</span></div>
) : (
+11 -6
View File
@@ -2,14 +2,19 @@ import { SignJWT, jwtVerify } from "jose";
import bcrypt from "bcryptjs";
import { query } from "@/lib/db";
import { cookies } from "next/headers";
import crypto from "crypto";
const RAW_SECRET = process.env.NODE_ENV === "production"
? process.env.JWT_SECRET
: crypto.randomUUID();
if (!RAW_SECRET) {
throw new Error("JWT_SECRET environment variable is required");
function randomHex(length: number): string {
const chars = "abcdef0123456789";
let result = "";
for (let i = 0; i < length; i++) {
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}
const g = globalThis as typeof globalThis & { __JWT_RAW_SECRET?: string };
const RAW_SECRET = process.env.JWT_SECRET || (g.__JWT_RAW_SECRET ??= randomHex(32));
if (!RAW_SECRET) throw new Error("JWT_SECRET environment variable is required");
const JWT_SECRET = new TextEncoder().encode(RAW_SECRET);
export const SESSION_COOKIE = "session";
+1 -18
View File
@@ -1,12 +1,5 @@
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
import { jwtVerify } from "jose"
const RAW_SECRET = process.env.JWT_SECRET
if (!RAW_SECRET) {
throw new Error("JWT_SECRET environment variable is required")
}
const JWT_SECRET = new TextEncoder().encode(RAW_SECRET)
const publicRoutes = [
"/login",
@@ -41,17 +34,7 @@ export async function middleware(request: NextRequest) {
return NextResponse.redirect(loginUrl)
}
try {
await jwtVerify(sessionCookie, JWT_SECRET)
return NextResponse.next()
} catch {
if (pathname.startsWith("/api/")) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
}
const loginUrl = new URL("/login", request.url)
loginUrl.searchParams.set("redirect", pathname)
return NextResponse.redirect(loginUrl)
}
return NextResponse.next()
}
export const config = {