During the migration from Axios to fetch, we overlooked the fact that Axios automatically handled CSRF tokens, while fetch does not. When CSRF protection was turned on, requests were failing with an "invalid CSRF token" error for users accessing the app even via HTTPS. This commit overrides fetch to ensure that the CSRF token is included in all requests. fix #1011
47 lines
1.2 KiB
TypeScript
47 lines
1.2 KiB
TypeScript
const getCsrfToken = (): string | null => {
|
|
if (typeof window !== 'undefined') {
|
|
const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);
|
|
return match ? decodeURIComponent(match[1]) : null;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
const isSameOrigin = (url: RequestInfo | URL): boolean => {
|
|
const parsedUrl = new URL(
|
|
url instanceof Request ? url.url : url.toString(),
|
|
window.location.origin
|
|
);
|
|
return parsedUrl.origin === window.location.origin;
|
|
};
|
|
|
|
// We are using a custom fetch implementation to add the X-XSRF-TOKEN heade
|
|
// to all requests. This is required when CSRF protection is enabled.
|
|
if (typeof window !== 'undefined') {
|
|
const originalFetch: typeof fetch = window.fetch;
|
|
|
|
(window as typeof globalThis).fetch = async (
|
|
input: RequestInfo | URL,
|
|
init?: RequestInit
|
|
): Promise<Response> => {
|
|
if (!isSameOrigin(input)) {
|
|
return originalFetch(input, init);
|
|
}
|
|
|
|
const csrfToken = getCsrfToken();
|
|
|
|
const headers = {
|
|
...(init?.headers || {}),
|
|
...(csrfToken ? { 'XSRF-TOKEN': csrfToken } : {}),
|
|
};
|
|
|
|
const newInit: RequestInit = {
|
|
...init,
|
|
headers,
|
|
};
|
|
|
|
return originalFetch(input, newInit);
|
|
};
|
|
}
|
|
|
|
export {};
|