CSRF problem using Sprig on a loop of Wishlist (Verbb) add/remove from list or products 'add to cart.
See original GitHub issueDescribe the bug
We are having issues may be something we are missing so apologies if it is. 😃
We get a CSRF problem using Sprig more than one form/button of Wishlist (Verbb) add/remove from list or products 'add to cart (Craft Commerce).
If you click the button to add/remove it will work for one of two buttons, in the browser console network tab it shows 400 Bad Request, and the response is ‘Unable to verify your data submission.’ This points to CSRF; if we turn off CSRF in the .config (‘enableCsrfProtection’ => false in the config) it all works fine again.
It happens only on the first load of the page eg for new users; if you reload the page, it works fine.
We have done a lot of testing… both on our server and on a new server installed with only Craft, Sprig, Blitz, Wishlist plugins. Only blitz/remove index.php in the .htaccess and basic version of the templates.
First though it was a Blitz/Sprig thing, but it happens if Blitz is off too.
If we do a Sprig call in a loop or even just two calls like below, it does not work on the first load:
main.twig
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sprig / Blitz / Wishlist TEST</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<h1 class="text-3xl font-bold underline">
Sprig / Blitz / Wishlist TEST
</h1>
<div id="content">
{# normaly a loop #}
Home
{{ sprig('_components/wishlist', {'entryId': 2}, {'s-trigger': 'load'}) }}
News
{{ sprig('_components/wishlist', {'entryId': 62}, {'s-trigger': 'load'}) }}
{# normaly a loop end #}
</div>
</body>
{{ sprig.script }}
</html>
_components/wishlist.twig
{% if sprig.isRequest %}
{% set item = craft.wishlist.item(entryId) %}
{% if item.inList %}
{# Posts to the `remove` action on click #}
<form sprig s-action="wishlist/items/remove" s-method="post" name="removeForm_{{ entryId }}" id="removeForm_{{ entryId }}">
<input type="hidden" name="elementId" value="{{ entryId }}">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-red-600 hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500">
Remove from wishlist
</button>
</form>
{% else %}
{# Posts to the `add` action on click #}
<form sprig s-action="wishlist/items/add" s-method="post" name="addForm_{{ entryId }}" id="addForm_{{ entryId }}">
<input type="hidden" name="elementId" value="{{ entryId }}">
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-green-500">
Add to wishlist
</button>
</form>
{% endif %}
{% endif %}
To reproduce
Steps to reproduce the behaviour:
- Make sure the pages are cached by checking the Blitz comment at the bottom of the HTML source.
- The way we get it to break is to open Firefox (Clear the cache in the preferences) It’s the same on Chrome/Edge too.
- Enter the URL, on the first load only one of the forms/buttons will work. The other will give a 400 error.
Expected behaviour
Expected both buttons to work. 😃
Versions
- Plugin version: Sprig 1.11.0, Blitz 3.11.1, Wishlist 1.4.11
- Craft version: 3.7.33 - also tried on 3.7.28, which had the same problem (before Craft CMS 3.7.33 - 2022-02-15, which notes: The way CSRF tokens are generated has changed in this release, so all users will be logged out during the update.)
Issue Analytics
- State:
- Created 2 years ago
- Comments:9
Top GitHub Comments
Probably, yes. It’s one of the many reasons that I always recommend one big Sprig component over many small ones, it just keeps everything simpler and more robust.
You’re right that this is still an issue for first requests, @robzor. I’ve created a dedicated issue, along with a workaround, at https://github.com/putyourlightson/craft-sprig/issues/279.