From 364be66f1780ca96abd5523f48d68ed8dedb2c1e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Sat, 20 Jun 2026 11:09:35 +0000 Subject: [PATCH] Add meaningful message on CSRF failure --- src/backend/InvenTree/InvenTree/middleware.py | 26 +++++++++++++++++++ src/frontend/src/functions/auth.tsx | 4 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/backend/InvenTree/InvenTree/middleware.py b/src/backend/InvenTree/InvenTree/middleware.py index 98ffc08c22..0c6ff3c94b 100644 --- a/src/backend/InvenTree/InvenTree/middleware.py +++ b/src/backend/InvenTree/InvenTree/middleware.py @@ -106,6 +106,32 @@ apps_mfa_bypass = [ """App namespaces that bypass MFA enforcement - normal security model is still enforced.""" +def csrf_failure(request, reason=''): + """Custom CSRF failure handler. + + Returns a JSON response for API/headless requests so the frontend can + provide a meaningful error message to the user + """ + from django.views.csrf import csrf_failure as django_default + + if ( + request.path.startswith('/_allauth/') + or request.path.startswith('/api/') + or 'application/json' in request.headers.get('Accept', '') + or 'application/json' in request.headers.get('Content-Type', '') + ): + return JsonResponse( + { + 'detail': _( + 'CSRF verification failed. Ensure INVENTREE_SITE_URL and INVENTREE_TRUSTED_ORIGINS are configured correctly.' + ) + }, + status=403, + ) + + return django_default(request, reason=reason) + + class AuthRequiredMiddleware: """Check for user to be authenticated.""" diff --git a/src/frontend/src/functions/auth.tsx b/src/frontend/src/functions/auth.tsx index 6f541f049c..2c940df733 100644 --- a/src/frontend/src/functions/auth.tsx +++ b/src/frontend/src/functions/auth.tsx @@ -131,7 +131,9 @@ export async function doBasicLogin( default: notifications.show({ title: `${t`Login failed`} (${err.response.status})`, - message: t`Check your input and try again.`, + message: + err.response?.data?.detail ?? + t`Check your input and try again.`, id: 'auth-login-error', color: 'red' });