Generic Example: BFF Route Handler Proxy
This example shows the standard BFF responsibilities in one place:
- CSRF validation for unsafe methods
- read access token from HttpOnly cookie (server-side)
- call backend via server-only
BACKEND_BASE_URL - attach
Authorization: Bearer ...
// app/api/v1/things/route.ts
import { cookies, headers } from "next/headers";
function assertSameOrigin(origin: string | null, referer: string | null) {
// Project-specific; keep strict. Reject when missing for unsafe methods if needed.
}
function validateCsrf(req: Request) {
if (!["POST", "PUT", "PATCH", "DELETE"].includes(req.method)) return;
const origin = req.headers.get("origin");
const referer = req.headers.get("referer");
assertSameOrigin(origin, referer);
const csrfCookie = cookies().get("csrf_token")?.value;
const csrfHeader = req.headers.get("x-csrf-token");
if (!csrfCookie || !csrfHeader || csrfCookie !== csrfHeader) {
throw new Error("CSRF validation failed");
}
}
export async function POST(req: Request) {
validateCsrf(req);
const accessJwt = cookies().get("access_token")?.value;
if (!accessJwt) return Response.json({ success: false, title: "Unauthorized" }, { status: 401 });
const backendBaseUrl = process.env.BACKEND_BASE_URL;
if (!backendBaseUrl) return Response.json({ success: false, title: "Misconfigured" }, { status: 500 });
const requestId = headers().get("x-request-id") || undefined;
const upstream = await fetch(`${backendBaseUrl}/api/v1/things`, {
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Bearer ${accessJwt}`,
...(requestId ? { "x-request-id": requestId } : {}),
},
body: await req.text(),
});
const body = await upstream.json().catch(() => ({}));
return Response.json(body, { status: upstream.status });
}