Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

x10Corey's avatar

Livewire 3 and Stripe

Hi All,

I have a multi-step order form with Livewire, on the last step the customer has the option to enter credit card information to be stored and used later, I'm using Stripe elements to show the CC info form. We need to provide Stripe a return_url in the case 3DS or other payment verification is needed. I can not figure out how to handle the case where Stripe redirects the user.

For example, customer picks products, fills out billing info, then they enter their CC info on the Stripe form and hit save. They get redirected back to my return_url which refreshes the page, losing that they were on the last step and other info, just as if they hit F5 on their keyboard.

What is the best way to handle this situation?

Thanks!

0 likes
3 replies
LaryAI's avatar
Level 58

To handle the situation where Stripe redirects the user back to your application after a 3D Secure (3DS) or other payment verification, you can use a combination of Livewire's state management and session storage to preserve the user's progress and data.

Here's a step-by-step solution:

  1. Store the Current Step and Data in the Session: Before redirecting to Stripe for 3DS verification, store the current step and any necessary data in the session. This way, you can retrieve it when the user is redirected back.

  2. Retrieve the Data After Redirection: When the user is redirected back to your application, check the session for the stored step and data, and use it to restore the user's progress.

  3. Update Your Livewire Component: Modify your Livewire component to handle storing and retrieving data from the session.

Here is an example implementation:

Livewire Component

use Livewire\Component;

class OrderForm extends Component
{
    public $step = 1;
    public $billingInfo = [];
    public $products = [];
    public $paymentIntentId;

    public function mount()
    {
        // Check if there's a session data to restore
        if (session()->has('order_form_data')) {
            $data = session('order_form_data');
            $this->step = $data['step'];
            $this->billingInfo = $data['billingInfo'];
            $this->products = $data['products'];
            $this->paymentIntentId = $data['paymentIntentId'];
        }
    }

    public function saveAndRedirectToStripe()
    {
        // Store the current state in the session
        session([
            'order_form_data' => [
                'step' => $this->step,
                'billingInfo' => $this->billingInfo,
                'products' => $this->products,
                'paymentIntentId' => $this->paymentIntentId,
            ]
        ]);

        // Redirect to Stripe for 3DS verification
        return redirect()->to($this->getStripeRedirectUrl());
    }

    public function getStripeRedirectUrl()
    {
        // Generate the Stripe redirect URL with the return_url
        // This is just a placeholder, replace with actual Stripe logic
        return 'https://stripe.com/3ds/redirect?return_url=' . route('stripe.return');
    }

    public function render()
    {
        return view('livewire.order-form');
    }
}

Routes

Define a route to handle the return from Stripe:

use Illuminate\Support\Facades\Route;

Route::get('/stripe/return', function () {
    // Clear the session data if needed
    session()->forget('order_form_data');

    // Redirect back to the Livewire component
    return redirect()->route('order.form');
})->name('stripe.return');

Blade Template

In your Blade template, ensure you have a form that triggers the saveAndRedirectToStripe method:

<div>
    @if ($step === 1)
        <!-- Step 1: Product Selection -->
    @elseif ($step === 2)
        <!-- Step 2: Billing Info -->
    @elseif ($step === 3)
        <!-- Step 3: Payment Info -->
        <form wire:submit.prevent="saveAndRedirectToStripe">
            <!-- Stripe Elements form -->
            <button type="submit">Save and Pay</button>
        </form>
    @endif
</div>

Explanation

  1. Mount Method: When the component mounts, it checks if there's any session data to restore. If so, it sets the component's properties accordingly.
  2. saveAndRedirectToStripe Method: This method stores the current state in the session and redirects the user to Stripe for 3DS verification.
  3. getStripeRedirectUrl Method: This method generates the Stripe redirect URL with the return URL.
  4. Route Handling: The /stripe/return route handles the return from Stripe, clears the session data if needed, and redirects back to the Livewire component.

By following this approach, you can ensure that the user's progress and data are preserved even after being redirected by Stripe for 3DS verification.

martinbean's avatar

@x10corey Stripe presents any requests for additional payment information (i.e. 3D Secure) as modals.

Re-reading the Stripe docs for the payment element (https://docs.stripe.com/payments/quickstart) it has this sample code:

const { error } = await stripe.confirmPayment({
  elements,
  confirmParams: {
    // Make sure to change this to your payment completion page
    return_url: "http://localhost:4242/checkout.html",
  },
});

So, as the comment suggests, change the return URL to be the payment completion page. If a user is checking out, then you should have some sort of cart or checkout or order identifier that you can use for a route that checks if the order is complete or not, i.e. /orders/{order}/complete.

1 like
x10Corey's avatar

@martinbean Thanks for the reply!

By default it seems it will always redirect with the URL unless you tell it not to: "redirect 'always' | 'if_required' By default, stripe.confirmSetup will always redirect to your return_url after a successful confirmation. If you set redirect: "if_required", then stripe.confirmSetup will only redirect if your user chooses a redirect-based payment method."

My concern is the wording here: "Stripe displays a modal for 3D Secure authentication or redirects the customer to an authentication page, depending on the payment method."

I know some payment methods do other authentication that is not necessarily 3DS, my fear would be that one of those cases occurs and my app is not setup to handle it.

My current page flow shows the customer's current payment methods or none, allows them to add a new one, if they do, it adds it to the list and auto selects it. But they can still choose a different payment method or add another one before hitting the submit order button. If I wanted to use the return_url to a checkout page or something similar I'd have to change my current setup around a bit.

Knowing all this, I think saving state to the session like the AI suggested might be my only option?

Please or to participate in this conversation.