craftcms / commerce-stripe

Stripe payment gateway for Craft Commerce
https://plugins.craftcms.com/commerce-stripe
MIT License
31 stars 48 forks source link

400 Unable to verify data submission #310

Open harry2909 opened 2 months ago

harry2909 commented 2 months ago

Description

Whenever I navigate to the payment page, the stripe form just renders a 400 error.

We're using blitz caching alongside a static caching solution, but this page should be omitted from the cache.

I can see in the request, the craft CSRF token is not added to the automatic post to the endpoint.

action: commerce/payments/pay
redirect: 80aabe5f62fc4cd38802a416a9aba3031d17816ea7134bea6897057175ab9ecchttps://drivedevilbiss.co.uk.ddev.site/store/customer/order?number=713e1c44d318b384db4c0c8127c6abdd&success=true
cancelUrl: abac018efdd9185f35742418abf2c89f6c4afd9048fec9d42589212d3ec6c146https://drivedevilbiss.co.uk.ddev.site/store/checkout/payment
orderEmail: dev@madebyextreme.com
gatewayId: 3

Payment form code:

 <form
                id="paymentForm"
                method="post"
                class="max-w-listing mx-auto {{ autoSubmitForm ? 'js-auto-submit' : '' }}"
            >
                <div class="flex flex-col lg:flex-row justify-between">
                    <div class="{{ cart.gatewayId == 1 ? 'mx-auto' : 'mr-[20px]' }} max-w-[700px] w-full p-8 lg:p-10 bg-white rounded-xl border border-ddh-grey-border self-start mb-[20px]">

                        {% if cart.gatewayId == 1 %}
                                <div class="text-center">
                                    {% if autoSubmitForm %}
                                        <p class="text-2xl font-heading font-medium pb-2">Loading...</p>
                                        <p class="text-sm">
                                            The browser should automatically continue, click the button to manually continue.
                                        </p>
                                        <div class="py-3">
                                            {% include '_partials/spinner' %}
                                        </div>
                                        {% include "_partials/button" with {
                                            element: 'button',
                                            type: 'submit',
                                            text: 'Continue',
                                            style: 1,
                                        } %}
                                    {% else %}
                                        <p class="text-2xl font-heading font-medium pb-2">There was a problem.</p>
                                        <p class="text-sm">{{ flashMessages.checkoutInvoicePaymentMethodFailedMessage }}</p>
                                        {% for key, errors in cart.getErrors() %}
                                            {% for error in errors %}
                                                {% if loop.first %}<ul>{% endif %}
                                                <li class="text-red-600"><strong>{{ key }}</strong> {{ error }}</li>
                                                {% if loop.last %}</ul>{% endif %}
                                            {% endfor %}
                                        {% endfor %}
                                        {% include "_partials/button" with {
                                            element: 'a',
                                            href: '/store/checkout/payment-method',
                                            text: 'Go back',
                                            style: 3,
                                            extraClasses: 'mt-4',
                                        } %}
                                    {% endif %}
                                </div>
                        {% endif %}

                        {% if cart.gatewayId %}

                            {% if paymentForm is defined %}
                                {% for key, errors in paymentForm.getErrors() %}
                                    {% for error in errors %}
                                        {% if loop.first %}<ul>{% endif %}
                                        <li class="text-red-600"><strong>{{ key }}</strong> {{ error }}</li>
                                        {% if loop.last %}</ul>{% endif %}
                                    {% endfor %}
                                {% endfor %}
                            {% endif %}

                            {{ actionInput('commerce/payments/pay') }}
                            {{ redirectInput(siteUrl('/store/customer/order', { number: cart.number, success: 'true' })) }}
                            {{ hiddenInput('cancelUrl', siteUrl('/store/checkout/payment')|hash) }}
                            {{ hiddenInput('orderEmail', cart.email) }}
                            {{ csrfInput() }}

                            {{ hiddenInput('gatewayId', cart.gatewayId) }}
                            {% set params = {
                                submitButtonClasses: 'mt-4 inline-flex border-2 border-transparent transition-colors relative rounded-4xl text-white font-heading font-bold leading-tight py-5 pr-14 pl-8 bg-ddh-yellow-dark items-center leading-normal text-center justify-center pr-8 w-full mt-8 hover:bg-white hover:border-ddh-yellow-dark hover:text-ddh-yellow-dark',
                                submitButtonText: 'Pay',
                            } %}

                            {% namespace cart.gateway.handle|commercePaymentFormNamespace %}
                                {{ cart.gateway.getPaymentFormHtml(params)|raw }}
                            {% endnamespace %}

                        {% endif %}
                    </div>

                    {% if cart.gatewayId != 1 %}
                        <div class="flex flex-wrap content-start justify-end lg:justify-between items-baseline xl:ml-4">
                            {{ include('store/checkout/_includes/order-summary', { showShippingAddress: true, showShippingMethod: true, }) }}
                        </div>
                    {% endif %}
                </div>
            </form>

image

It is worth noting that this worked absolutely fine until I set enableCsrfProtection to true in the general config, which does make sense. We needed this true so that asyncCsrfInputs would work.

I've tested and setting asyncCsrfInputs to false does make it work, so it could be to do with this.

Please let me know if you need any more information.

Steps to reproduce

1. 2.

Additional info

linear[bot] commented 2 months ago

PT-2122 400 Unable to verify data submission

jonnykates commented 2 months ago

Also experiencing this with Commerce 4.6.11 and Stripe for Craft Commerce 4.1.5.

I've got a form on my payment page like;

<form method="post" id="payment-form" action="">
        {{ csrfInput() }}
        {{ actionInput('commerce/payments/pay') }}
        {{ redirectInput(siteUrl('/shop/checkout/order?number=' ~ cart.number) )}}
        {{ hiddenInput('cancelUrl', siteUrl('/shop/checkout/payment')|hash) }}
        {{ hiddenInput('orderEmail', cart.email) }}

        {{ cart.gateway.getPaymentFormHtml({})|raw }}
</form>

And with asyncCsrfInputs set to true in general config, the Stripe element doesn't render but shows 'Unable to verify your data submission'.

lukeholder commented 1 month ago

@jonnykates

Does using {{ csrfInput({ async: false }) }} in the payment form fix this issue?