Routes protected by the _csrf_token: 'TRUE' requirement generate and validate their CSRF token against the full route path, including all parameters. This breaks when a route parameter legitimately changes between the link being rendered and the request being made: most notably Drupal core's own AJAX system, which rewrites nojs to ajax in the URL (via ajax.js) for links using the use-ajax class. Because the path used to validate the token no longer matches the path used to generate it, the CSRF check fails and access is denied even though the request is legitimate.
A new route option, _csrf_exclude_parameters, has been added. It accepts an array of route parameter names that should be ignored when building the path used to generate and validate the _csrf_token. Routes that use a parameter which is expected to change between rendering and request (such as a nojs/ajax toggle) can list that parameter to exclude it from the token calculation, so the token still matches.
If _csrf_exclude_parameters is not set, existing behavior is unchanged: all route parameters are included in the path for tokenization.
Before
A route using a nojs/ajax parameter alongside _csrf_token fails CSRF validation on the AJAX request, because ajax.js swaps nojs for ajax in the path after the token was generated:
flag.link_unflag:
path: '/flag/unflag/{flag}/{entity_id}/{js}'
defaults:
_controller: '\Drupal\flag\Controller\LinkController::unflag'
requirements:
_custom_access: '\Drupal\flag\FlagAccessController::checkUnflag'
_csrf_token: 'TRUE'
js: 'nojs|ajax'
After
Route authors can add _csrf_exclude_parameters to the route's options, listing the parameter(s) that should not be part of the CSRF token path:
flag.link_unflag:
path: '/flag/unflag/{flag}/{entity_id}/{js}'
defaults:
_controller: '\Drupal\flag\Controller\LinkController::unflag'
requirements:
_custom_access: '\Drupal\flag\FlagAccessController::checkUnflag'
_csrf_token: 'TRUE'
js: 'nojs|ajax'
options:
_csrf_exclude_parameters: ['js']
With this option set, the js parameter's value (nojs vs ajax) no longer affects the generated/validated token, so the same link works whether or not JavaScript rewrites the path.
AI usage declaration
Claude Sonnet 5 assisted in the drafting of this change notice, but all text has been reviewed and approved by a human too.