Skip to content

Commit

Permalink
fix: fetch override to attach XSRF token to fix csrfProtection issue
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Fallenbagel committed Oct 16, 2024
1 parent a0f80fe commit eba009d
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { SettingsProvider } from '@app/context/SettingsContext';
import { UserContext } from '@app/context/UserContext';
import type { User } from '@app/hooks/useUser';
import '@app/styles/globals.css';
import '@app/utils/fetchOverride';
import { polyfillIntl } from '@app/utils/polyfillIntl';
import { MediaServerType } from '@server/constants/server';
import type { PublicSettingsResponse } from '@server/interfaces/api/settingsInterfaces';
Expand Down
46 changes: 46 additions & 0 deletions src/utils/fetchOverride.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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 {};

0 comments on commit eba009d

Please sign in to comment.