Problem
Both, the core menu linkset, and the REST menu items module face the same issue: Since Drupal 10.3/11 the user logout link contains a CSRF token. However, the token provided by the API is invalid.
Note that this worked fine for Drupal 10.2 and before, so this is a regression that causes decoupled solutions that fetch the "account" menu to break.
Related issue for REST menu items module:
π
Wrong user logout CSRF token
Active
Steps to reproduce
* Access the "account" menu
* Try using the logout link, when the token is valid, it should work without confirmation form.
* The token is not valid, a confirmation form is shown
The token does not work, because it's not the token. The value for the token is the render-placeholder, but the placeholder never gets replaced. API modules rendering to JSON to not use the render system, thus never get placeholders replaced. Still, RouteProcessorCsrf() placeholders the value.
Analysis
The problematic logic is in `\Drupal\Core\Access\RouteProcessorCsrf::processOutbound`.
// Adding this to the parameters means it will get merged into the query
// string when the route is compiled.
if (!$bubbleable_metadata) {
$parameters['token'] = $this->csrfToken->get($path);
}
else {
// Generate a placeholder and a render array to replace it.
$placeholder = Crypt::hashBase64($path);
$placeholder_render_array = [
'#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
];
....
However, the assumption "we have cachemetadata, thus we can use placeholders" is wrong. JSON API response should use cache metadata, but cannot use render API placeholders. Not sure what else would be a good indicator on when to placeholder it, but the current one isn't it.
To reproduce, a simple generated URL like
> \Drupal\Core\Url::fromUri('internal:/user/logout')->toString();
will generate an invalid token. (note that you need to use the right session also!)
Remaining tasks
Figure out when it's safe to placeholder the token and change the logic. Maybe we check for an active render context instead?