phplaravelstripe-paymentslaravel-cashierlaravel-spark

Laravel Spark 403 - REDIRECT HOST MISMATCH when 3D Secure Payment


I am using Laravel Spark for billing my customers. In case they will pay with 3D Secure cards (I test it with card no. from stripe doc's https://stripe.com/docs/testing#regulatory-cards: 4000 0027 6000 3184) I have the following problem:

The stripe pop-up/modal opens and I click 'Complete Authentication'.

enter image description here

After that the authentication process starts and the user gets directed to http://127.0.0.1:8000/stripe/payment/pi_xxx?redirect=/home

Here I get the following Laravel error (I do not find other error causes in console or somewhere else):

403-error

I've added stripe/* in VerifyCsrfToken Class already... Maybe do I need to test this case on my server?

Very weird and I guess thats a sign that I do not have any issues with stripe, with laravel instead. When I remove the query parameter ?redirect=home I get this screen:

enter image description here

When I proceed I do not get redirected.. Of course because there is no redirect uri...

Does any one had this issue before?


Solution

  • For me this is a bug in Spark. I've searched for all occurences where Stripe used a redirect. One indication for me that this could really be a bug is:

    In subscription-notice.blade.php file there ist the link build as follows:

    {!! __('Please :linkOpen confirm your payment :linkClose to activate your subscription!', ['linkOpen' => '<a href="/'.config('cashier.path').'/payment/'.auth()->user()->subscription()->latestPayment()->id.'?redirect='.url('/home').'">', 'linkClose' => '</a>']) !!}
    

    The part '?redirect='.url('/home').' creates a full valid URL with host address. Not only a relative path! These relative paths runs into the 403 Error in my case. Like in the RegisterController:

    /**
     * Handle a registration request for the application.
     *
     * @param  \Laravel\Spark\Contracts\Http\Requests\Auth\RegisterRequest  $request
     * @return \Illuminate\Http\Response
     */
    public function register(RegisterRequest $request)
    {
        list($user, $paymentId) = Spark::interact(
            Register::class, [$request]
        );
    
        Auth::login($user);
    
        event(new UserRegistered($user));
    
        if ($user instanceof MustVerifyEmail && ! $user->hasVerifiedEmail()) {
            $user->sendEmailVerificationNotification();
        }
    
        return response()->json([
            'redirect' => $paymentId ?
                '/'.config('cashier.path').'/payment/'.$paymentId.'?redirect='.$this->redirectPath()
                : $this->redirectPath(),
        ]);
    }
    

    $this->redirectPath() returns a relative path. I've changed this part into:

    return response()->json([
            'redirect' => $paymentId ?
                '/'.config('cashier.path').'/payment/'.$paymentId.'?redirect='.config('app.url').$this->redirectPath()
                : $this->redirectPath(),
        ]);
    

    In this case I took the host address from my config and put it in front of the relative path.

    Just for better understanding, the returned URL above is used here (register-stripe.js):

        /*
         * After obtaining the Stripe token, send the registration to Spark.
         */
        sendRegistration(paymentMethod) {
            this.registerForm.stripe_payment_method = paymentMethod;
    
            Spark.post('/register', this.registerForm)
                .then(response => {
                    window.location = response.redirect;
                });
        }
    

    There are some more cases where I needed to override some JavaScript or PHP sources...

    I hope I could help others with that! If necessary I could also post the exact places where I've changed the redirect URL in the comments.