Enhanced error message on CSRF failure (#12788)

* Enhanced error message on CSRF failure

* Defer to 'detail' field if exists
This commit is contained in:
Oliver
2026-09-05 19:55:37 +10:00
committed by GitHub
parent 0a4f095397
commit 9a416df5d4
3 changed files with 20 additions and 15 deletions
+10 -8
View File
@@ -113,7 +113,9 @@ 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
provide a meaningful error message to the user.
This Includes Django's own message (e.g. "CSRF cookie not set.") alongside the generic hint.
"""
from django.views.csrf import csrf_failure as django_default
@@ -123,15 +125,15 @@ def csrf_failure(request, reason=''):
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,
detail = _(
'CSRF verification failed. Ensure INVENTREE_SITE_URL and INVENTREE_TRUSTED_ORIGINS are configured correctly.'
)
if reason:
detail = f'{detail} ({reason})'
return JsonResponse({'detail': detail}, status=403)
return django_default(request, reason=reason)
@@ -310,7 +310,7 @@ class MiddlewareTests(InvenTreeTestCase):
request.META[f'HTTP_{key.upper().replace("-", "_")}'] = value
return request
# API path -> JSON 403 with meaningful message
# API path -> JSON 403 with meaningful message, plus Django's own reason
response = csrf_failure(
make_request('/api/part/'), reason='origin check failed'
)
@@ -318,9 +318,9 @@ class MiddlewareTests(InvenTreeTestCase):
import json
data = json.loads(response.content)
self.assertEqual(data['detail'], EXPECTED_DETAIL)
self.assertEqual(data['detail'], f'{EXPECTED_DETAIL} (origin check failed)')
# allauth headless path -> JSON 403
# allauth headless path -> JSON 403 (no reason supplied -> generic message only)
response = csrf_failure(make_request('/_allauth/browser/v1/auth/login'))
self.assertEqual(response.status_code, 403)
data = json.loads(response.content)
@@ -333,16 +333,16 @@ class MiddlewareTests(InvenTreeTestCase):
)
self.assertEqual(response.status_code, 403)
data = json.loads(response.content)
self.assertEqual(data['detail'], EXPECTED_DETAIL)
self.assertEqual(data['detail'], f'{EXPECTED_DETAIL} (origin check failed)')
# Content-Type: application/json header -> JSON 403
response = csrf_failure(
make_request('/some/other/path/', {'Content-Type': 'application/json'}),
reason='origin check failed',
reason='CSRF cookie not set.',
)
self.assertEqual(response.status_code, 403)
data = json.loads(response.content)
self.assertEqual(data['detail'], EXPECTED_DETAIL)
self.assertEqual(data['detail'], f'{EXPECTED_DETAIL} (CSRF cookie not set.)')
# Plain browser request -> falls back to Django default CSRF page (403 HTML, not JSON)
response = csrf_failure(make_request('/web/'), reason='origin check failed')
+4 -1
View File
@@ -20,7 +20,10 @@ export function extractErrorMessage({
let message = '';
if (error_data) {
message = error_data[field ?? 'error'] ?? error_data['non_field_errors'];
message =
error_data[field ?? 'error'] ??
error_data['detail'] ??
error_data['non_field_errors'];
}
// No message? Look at the response status codes