fix: auto-issue CSRF cookie for existing sessions

Sessions from before CSRF was added lack the bh-csrf-token cookie,
causing 403 on first save. Middleware now auto-generates the cookie
if the user is authenticated but missing it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-17 17:57:49 +03:00
parent 6cbdba2197
commit 7497ede2fd

View File

@@ -5,6 +5,14 @@ const CSRF_COOKIE_NAME = "bh-csrf-token";
const CSRF_HEADER_NAME = "x-csrf-token";
const STATE_CHANGING_METHODS = new Set(["POST", "PUT", "DELETE", "PATCH"]);
function generateCsrfToken(): string {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
let binary = "";
for (const b of array) binary += String.fromCharCode(b);
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
export async function proxy(request: NextRequest) {
const { pathname } = request.nextUrl;
@@ -24,6 +32,21 @@ export async function proxy(request: NextRequest) {
return NextResponse.redirect(new URL("/admin/login", request.url));
}
// Auto-issue CSRF cookie if missing (e.g. session from before CSRF was added)
const hasCsrf = request.cookies.has(CSRF_COOKIE_NAME);
if (!hasCsrf) {
const csrfToken = generateCsrfToken();
const response = NextResponse.next();
response.cookies.set(CSRF_COOKIE_NAME, csrfToken, {
httpOnly: false,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
path: "/",
maxAge: 60 * 60 * 24,
});
return response;
}
// CSRF check on state-changing API requests
if (pathname.startsWith("/api/admin/") && STATE_CHANGING_METHODS.has(request.method)) {
const csrfCookie = request.cookies.get(CSRF_COOKIE_NAME)?.value;