From 8dad0872ae3ebb6cd57008b3db61b4852f2409f9 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sat, 8 Nov 2025 11:11:06 +0000 Subject: [PATCH] Fix CSRF token parsing in config export/import (related to #646) The config backup export and import functions were incorrectly parsing the CSRF token from cookies, causing "Export requires authentication" errors even when users were properly logged in. Two issues were fixed: 1. Cookie parsing used `.split('=')[1]` which truncated tokens containing `=` padding characters (common in base64 tokens). Fixed by using `.split('=').slice(1).join('=')` to preserve the full value. 2. Missing URL decoding of the cookie value. Browsers percent-encode cookie values, so `=` becomes `%3D`. The backend then failed to match the encoded token hash. Fixed by adding `decodeURIComponent()`. Both fixes mirror the pattern already used in apiClient.ts. --- .../src/components/Settings/Settings.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend-modern/src/components/Settings/Settings.tsx b/frontend-modern/src/components/Settings/Settings.tsx index 011cfe4..c678a9d 100644 --- a/frontend-modern/src/components/Settings/Settings.tsx +++ b/frontend-modern/src/components/Settings/Settings.tsx @@ -1924,10 +1924,12 @@ const Settings: Component = (props) => { try { // Get CSRF token from cookie - const csrfToken = document.cookie + const csrfCookie = document.cookie .split('; ') - .find((row) => row.startsWith('pulse_csrf=')) - ?.split('=')[1]; + .find((row) => row.startsWith('pulse_csrf=')); + const csrfToken = csrfCookie + ? decodeURIComponent(csrfCookie.split('=').slice(1).join('=')) + : undefined; const headers: HeadersInit = { 'Content-Type': 'application/json', @@ -2051,10 +2053,12 @@ const Settings: Component = (props) => { } // Get CSRF token from cookie - const csrfToken = document.cookie + const csrfCookie = document.cookie .split('; ') - .find((row) => row.startsWith('pulse_csrf=')) - ?.split('=')[1]; + .find((row) => row.startsWith('pulse_csrf=')); + const csrfToken = csrfCookie + ? decodeURIComponent(csrfCookie.split('=').slice(1).join('=')) + : undefined; const headers: HeadersInit = { 'Content-Type': 'application/json',