payment-backoffice/middleware.ts
2025-10-25 11:39:24 +02:00

82 lines
2.1 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { jwtVerify } from "jose";
const COOKIE_NAME = "auth_token";
const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET!);
function isExpired(exp?: number) {
return exp ? exp * 1000 <= Date.now() : false;
}
async function validateToken(token: string) {
const raw = token.startsWith("Bearer ") ? token.slice(7) : token;
try {
const { payload } = await jwtVerify(raw, JWT_SECRET, {
algorithms: ["HS256"],
});
return payload as {
exp?: number;
MustChangePassword?: boolean;
[key: string]: unknown;
};
} catch (err) {
console.error("Token validation error:", err);
return null;
}
}
export async function middleware(request: NextRequest) {
const token = request.cookies.get(COOKIE_NAME)?.value;
const loginUrl = new URL("/login", request.url);
const currentPath = request.nextUrl.pathname;
// 1⃣ No token
if (!token) {
loginUrl.searchParams.set("reason", "no-token");
loginUrl.searchParams.set("redirect", currentPath);
return NextResponse.redirect(loginUrl);
}
// 2⃣ Validate + decode
const payload = await validateToken(token);
if (!payload) {
const res = NextResponse.redirect(loginUrl);
res.cookies.delete(COOKIE_NAME);
loginUrl.searchParams.set("reason", "invalid-token");
loginUrl.searchParams.set("redirect", currentPath);
return res;
}
// 3⃣ Expiry check
if (isExpired(payload.exp)) {
const res = NextResponse.redirect(loginUrl);
res.cookies.delete(COOKIE_NAME);
loginUrl.searchParams.set("reason", "expired-token");
loginUrl.searchParams.set("redirect", currentPath);
return res;
}
// 4⃣ Must change password check
if (payload.MustChangePassword) {
loginUrl.searchParams.set("reason", "change-password");
loginUrl.searchParams.set("redirect", currentPath);
return NextResponse.redirect(loginUrl);
}
// ✅ All good
return NextResponse.next();
}
export const config = {
matcher: [
"/dashboard/:path*",
"/settings/:path*",
"/admin/:path*",
"/change-password/:path*",
],
};