Problem
Starting with Drupal 10.3 and 11 the user.logout is protected with a CSRF token. Now the user logout link of the `account` menu has a token query parameter. With that token, the link just works. If the token is wrong, a confirmation forms is shown as fallback action.
It turns out that the user logout link provided by the rest-menu-items API contains a *wrong* token. It never passes validation. Open the absolute URL of the user.logout link.
Expected: You are logged out.
Actual: Log out does not work, the confirmation-form fallback is shown.
Note that the confirmation form is not helpful in decoupled environments, what makes this more severe.
Steps to reproduce
Launch D11, e.g. via the "try it" button at https://www.drupal.org/project/lupus_decoupled. Access the API via the URL `api/menu_items/account`.
First analysis
I verified session and seed is correct when token is generated and validated. However, somehow the token provided with the rest_menu_item menu link ends up being wrong. At some point there is also a right token generated on the menu-api request, but it does not end-up in the URL being generated.
Comments
Comment #2
fagoI tracked it down: the problem is the wrong token, is not a token, it's a placeholder, which ought to be replaced by the renderer.
See the logic of RouteProcessorCsrf:
\Drupal\Core\Render\MetadataBubblingUrlGenerator::generateFromRoute() seems to activate this logic always, even when the Url is generated with $url->toString(FALSE).
Comment #3
fagoto reproduce, run this with drush php
compare the token with the right token, it's wrong, it's the placeholder value. So seems this is triggered by a core bug.
However, additionally rest_menu_items has a bug since it calls > \Drupal\Core\Url::fromUri('internal:/user/logout')->toString(TRUE); but throws the resulting bubbleablemetadata away. By throwing it away, the placeholders won't be replaced.
Generally, I think the module should re-use the pre-existing $url object provided by the menu API and not re-create it with the uri. When done so, we'd not trigger bugs like this one.
Comment #4
fagoso, re-using the pre-exiting url object does not solve it either. Anyway, Drupal core generates the token with a placeholder, but since we are not rendering obviously placeholders are not replaced. :-( I wonder how this is solved for the drupal core menu linkset api.
Comment #5
fagotested it. it does not - it faces the same problem. Let's open a core issue!
--> #3485174: Menu APIs provide invalid CSRF tokens
Comment #6
fagoI can confirm this is fixed now. With the fix in core, this works, so let's mark this as fixed also!