From 62cc6c07d1b88109666a304b1825dd32adec58d0 Mon Sep 17 00:00:00 2001 From: Petru Paler Date: Thu, 8 Jan 2026 16:09:21 +0000 Subject: [PATCH] Add CSRF token to event delete fetch() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The delete event functionality uses vanilla fetch() instead of HTMX, so it wasn't getting the x-csrf-token header that the htmx:configRequest listener adds. This caused 403 Forbidden on event deletion. Changes: - Made getCsrfToken() a global window function so it can be used by both HTMX and vanilla fetch() calls - Added x-csrf-token header to the deleteEvent() fetch request 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/animaltrack/web/templates/base.py | 15 ++++++++------- src/animaltrack/web/templates/event_detail.py | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/animaltrack/web/templates/base.py b/src/animaltrack/web/templates/base.py index 26afa50..435d534 100644 --- a/src/animaltrack/web/templates/base.py +++ b/src/animaltrack/web/templates/base.py @@ -105,15 +105,16 @@ def EventSlideOverScript(): # noqa: N802 def CsrfHeaderScript(): # noqa: N802 - """JavaScript to inject CSRF token into HTMX requests. + """JavaScript to inject CSRF token into HTMX requests and provide global helper. - Reads the csrf_token cookie and adds it as x-csrf-token header - to all HTMX requests. This is required for POST/PUT/DELETE - requests to pass CSRF validation. + Provides a global getCsrfToken() function that reads the csrf_token cookie. + This function is used both by HTMX (via htmx:configRequest) and by any + vanilla fetch() calls that need CSRF protection. """ return Script(""" - // Read CSRF token from cookie - function getCsrfToken() { + // Global function to read CSRF token from cookie + // Used by HTMX config and available for vanilla fetch() calls + window.getCsrfToken = function() { var name = 'csrf_token='; var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { @@ -123,7 +124,7 @@ def CsrfHeaderScript(): # noqa: N802 } } return ''; - } + }; // Configure HTMX to send CSRF token with all requests document.body.addEventListener('htmx:configRequest', function(event) { diff --git a/src/animaltrack/web/templates/event_detail.py b/src/animaltrack/web/templates/event_detail.py index 1880b02..e498551 100644 --- a/src/animaltrack/web/templates/event_detail.py +++ b/src/animaltrack/web/templates/event_detail.py @@ -535,6 +535,7 @@ def delete_script() -> Script: method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', + 'x-csrf-token': getCsrfToken(), }, body: 'reason=Deleted via UI' });