fix proxy csrf handling for suggestion requests

This commit is contained in:
alex wiesner
2026-03-14 12:59:35 +00:00
parent 4b3f432640
commit 566077533b
2 changed files with 42 additions and 17 deletions

View File

@@ -1,8 +1,22 @@
const PUBLIC_SERVER_URL = process.env['PUBLIC_SERVER_URL'];
const serverEndpoint = PUBLIC_SERVER_URL || 'http://localhost:8000';
export const fetchCSRFToken = async () => {
const csrfTokenFetch = await fetch(`${serverEndpoint}/csrf/`);
type FetchCSRFTokenOptions = {
fetch?: typeof fetch;
sessionId?: string;
};
export const fetchCSRFToken = async (options: FetchCSRFTokenOptions = {}) => {
const fetchFn = options.fetch ?? fetch;
const headers = new Headers();
if (options.sessionId) {
headers.set('Cookie', `sessionid=${options.sessionId}`);
}
const csrfTokenFetch = await fetchFn(`${serverEndpoint}/csrf/`, {
headers
});
if (csrfTokenFetch.ok) {
const csrfToken = await csrfTokenFetch.json();
return csrfToken.csrfToken;

View File

@@ -43,7 +43,7 @@ async function handleRequest(
const path = params.path;
let targetUrl = `${endpoint}/api/${path}`;
// Ensure the path ends with a trailing slash
// Preserve global proxy contract for mutating requests.
if (requreTrailingSlash && !targetUrl.endsWith('/')) {
targetUrl += '/';
}
@@ -53,27 +53,38 @@ async function handleRequest(
const headers = new Headers(request.headers);
// Delete existing csrf cookie by setting an expired date
cookies.delete('csrftoken', { path: '/' });
const isMutatingRequest = !['GET', 'HEAD', 'OPTIONS'].includes(request.method.toUpperCase());
const sessionId = cookies.get('sessionid');
let csrfToken: string | null = null;
// Generate a new csrf token (using your existing fetchCSRFToken function)
const csrfToken = await fetchCSRFToken();
if (!csrfToken) {
return json({ error: 'CSRF token is missing or invalid' }, { status: 400 });
if (isMutatingRequest) {
csrfToken = await fetchCSRFToken({ fetch, sessionId });
if (!csrfToken) {
return json({ error: 'CSRF token is missing or invalid' }, { status: 400 });
}
}
// Set the new csrf token in both headers and cookies
const sessionId = cookies.get('sessionid');
const cookieHeader = `csrftoken=${csrfToken}` + (sessionId ? `; sessionid=${sessionId}` : '');
const cookieParts: string[] = [];
if (csrfToken) cookieParts.push(`csrftoken=${csrfToken}`);
if (sessionId) cookieParts.push(`sessionid=${sessionId}`);
const cookieHeader = cookieParts.join('; ');
const forwardedHeaders = {
...Object.fromEntries(headers)
} as Record<string, string>;
if (csrfToken) {
forwardedHeaders['X-CSRFToken'] = csrfToken;
}
if (cookieHeader) {
forwardedHeaders['Cookie'] = cookieHeader;
}
try {
const response = await fetch(targetUrl, {
method: request.method,
headers: {
...Object.fromEntries(headers),
'X-CSRFToken': csrfToken,
Cookie: cookieHeader
},
headers: forwardedHeaders,
body:
request.method !== 'GET' && request.method !== 'HEAD' ? await request.text() : undefined,
credentials: 'include' // This line ensures cookies are sent with the request