Replace HTTP Basic Auth with a branded /login flow and signed session cookie, using Next.js 16's proxy convention for route protection. Co-authored-by: Cursor <cursoragent@cursor.com>
51 lines
1.3 KiB
TypeScript
51 lines
1.3 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import type { NextRequest } from "next/server";
|
|
|
|
import {
|
|
AUTH_COOKIE_NAME,
|
|
safeRedirectPath,
|
|
verifyAccessToken,
|
|
} from "~/lib/site-auth";
|
|
|
|
/**
|
|
* Site-wide password gate via a login page and signed session cookie.
|
|
*
|
|
* Set `SITE_PASSWORD` in `.env` to require a password before the site loads.
|
|
* Leave `SITE_PASSWORD` unset to disable the gate.
|
|
*/
|
|
export async function proxy(req: NextRequest) {
|
|
const password = process.env.SITE_PASSWORD;
|
|
|
|
if (!password) return NextResponse.next();
|
|
|
|
const token = req.cookies.get(AUTH_COOKIE_NAME)?.value;
|
|
const isAuthed = await verifyAccessToken(password, token);
|
|
const { pathname } = req.nextUrl;
|
|
|
|
if (pathname === "/login" || pathname === "/api/auth") {
|
|
if (isAuthed && pathname === "/login") {
|
|
const from = safeRedirectPath(req.nextUrl.searchParams.get("from"));
|
|
return NextResponse.redirect(new URL(from, req.url));
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
if (!isAuthed) {
|
|
const loginUrl = new URL("/login", req.url);
|
|
const returnPath = pathname + req.nextUrl.search;
|
|
|
|
if (returnPath !== "/") {
|
|
loginUrl.searchParams.set("from", returnPath);
|
|
}
|
|
|
|
return NextResponse.redirect(loginUrl);
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ["/((?!_next/static|_next/image|favicon.ico|.*\\..*).*)"],
|
|
};
|