Skip to content

CSRF incompatibility with custom CSRF_HEADER_NAME #434

@kirpit

Description

@kirpit

CSRF incompatibility with custom CSRF_HEADER_NAME (still reproducible after #303 fix)

Related issue

Summary

django-admin-sortable2 still fails CSRF validation in Django projects that use:

  • CSRF_USE_SESSIONS = True, and
  • a custom CSRF header name via CSRF_HEADER_NAME (for example HTTP_X_AUTH_CSRFTOKEN).

The 2.0.2 fix for #303 addressed CSRF token retrieval from the hidden form input (works), but the JS request header key is still hardcoded to X-CSRFToken, which breaks when Django expects a custom header name.


Environment

  • Django: 5.2.x
  • django-admin-sortable2: 2.3.1
  • CSRF settings (example):
    • CSRF_USE_SESSIONS = True
    • CSRF_HEADER_NAME = "HTTP_X_AUTH_CSRFTOKEN"
    • project frontend convention header: X-Auth-CsrfToken

Reproduction

  1. Enable SortableAdminMixin on a Django admin model.
  2. Configure Django with:
    • CSRF_USE_SESSIONS = True
    • non-default CSRF_HEADER_NAME (example above)
  3. Open admin changelist and drag-reorder rows.
  4. Observe POST to:
    • /admin/<app>/<model>/adminsortable2_update/
  5. Response:
    • 403 Forbidden (CSRF token missing/incorrect)

Why this still happens after #303

Current JS correctly extracts token from hidden input, but appends it under a fixed header name.

File:

  • adminsortable2/static/adminsortable2/js/adminsortable2.js

Code path:

  • ListSortable.headers getter

Current logic (simplified):

const inputElement = this.tableBody.closest("form")?.querySelector('input[name="csrfmiddlewaretoken"]');
if (inputElement) {
  headers.append("X-CSRFToken", inputElement.value);
}

This ignores Django’s configurable CSRF_HEADER_NAME.

Equivalent behavior is present in adminsortable2.min.js.

Evidence

In a project with:

CSRF_USE_SESSIONS = True
CSRF_HEADER_NAME = "HTTP_X_AUTH_CSRFTOKEN"

Django expects request header X-Auth-CsrfToken (mapped internally to HTTP_X_AUTH_CSRFTOKEN), but sortable2 sends X-CSRFToken, so CSRF middleware rejects the request.

Expected behavior

django-admin-sortable2 should respect Django-configured CSRF header names, not only default X-CSRFToken.

Reliable fix proposal

Support configurable CSRF header key in sortable2 AJAX requests.

Pass client-side CSRF header name from backend/template config into JS (alongside update_url) and use:

headers.append(config.csrf_header || "X-CSRFToken", token);

This keeps backward compatibility and supports custom Django settings.

Why this should be supported

Django intentionally allows custom CSRF header names. Third-party admin JS should interoperate with Django’s CSRF settings to avoid requiring project-specific middleware hacks or disabling established CSRF conventions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions