Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel stripe payment form isn't handled just posted

I'm using the default card element from Stripe which can be found here. The form renders and the validation stripe includes works & renders. However, I never get a stripeToken generated so the subscription fails due to;

This customer has no attached payment source

When I die dump my requests the stripeToken is NULL. I think this is because the stripe form handler doesn't work at all for me, the event listener they include doesn't ever fire.

Looks like the form is just posting like a normal form instead of the prevent default JS listener added by stripe.

<form action="{{ route('subscriptionCreate') }}" method="post" id="payment-form">
  @csrf
  <input type="hidden" name="plan" value="{{ $plan->id }}">
  <div class="form-row">
    <label for="card-element">
      Credit or debit card
    </label>
    <div id="card-element">
      <!-- A Stripe Element will be inserted here. -->
    </div>

    <div id="card-errors" role="alert"></div>
  </div>

  <button>Submit Payment</button>
</form>

The Javascript included from the elements example;

<script>

// Create a Stripe client.
var stripe = Stripe('###Removed###');

// Create an instance of Elements.
var elements = stripe.elements();

// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
  base: {
    color: '#32325d',
    fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
    fontSmoothing: 'antialiased',
    fontSize: '16px',
    '::placeholder': {
      color: '#aab7c4'
    }
  },
  invalid: {
    color: '#fa755a',
    iconColor: '#fa755a'
  }
};

// Create an instance of the card Element.
var card = elements.create('card', {style: style});

// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');

// Handle real-time validation errors from the card Element.
card.addEventListener('change', function(event) {
  var displayError = document.getElementById('card-errors');
  if (event.error) {
    displayError.textContent = event.error.message;
  } else {
    displayError.textContent = '';
  }
});

// Handle form submission.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
  event.preventDefault();

  stripe.createToken(card).then(function(result) {
    if (result.error) {
      // Inform the user if there was an error.
      var errorElement = document.getElementById('card-errors');
      errorElement.textContent = result.error.message;
    } else {
      // Send the token to your server.
      stripeTokenHandler(result.token);
    }
  });
});


// // Submit the form with the token ID.
function stripeTokenHandler(token) {
  // Insert the token ID into the form so it gets submitted to the server
  var form = document.getElementById('payment-form');
  var hiddenInput = document.createElement('input');
  hiddenInput.setAttribute('type', 'hidden');
  hiddenInput.setAttribute('name', 'stripeToken');
  hiddenInput.setAttribute('value', token.id);
  form.appendChild(hiddenInput);

  // Submit the form
  form.submit();
}
</script>

This is my controller, as I mentioned the $request->stripeToken doesn't exist I don't think it ever gets added to the form.

public function create(Request $request)
{

    $plan = Plan::findOrFail($request->get('plan'));

    $user = $request->user();

    $request->user()
        ->newSubscription($plan->name, $plan->stripe_plan)
        ->create($request->stripeToken,[
            'email' => $user->email
        ]);

    return redirect()->route('home')->with('success', 'Your plan subscribed successfully');
}
like image 369
archvist Avatar asked Jul 21 '19 20:07

archvist


People also ask

How do I know if my Stripe payment was successful?

Stripe sends the payment_intent. succeeded event when payment is successful and the payment_intent. payment_failed event when payment isn't successful. When payment is unsuccessful, you can find more details by inspecting the PaymentIntent's last_payment_error property.

Why is Stripe payment incomplete?

Incomplete paymentsIt's just people that didn't finish the checkout. Some merchants have been worried by errors that appear in the logs when we're communicating with Stripe. These errors are normal and are Stripe's way of responding to bad data like misspelled emails or when the card couldn't be charged.


1 Answers

I've created https://jsfiddle.net/s8foxw9r/2/ that confirms the stripeTokenHandler is working (and the token is being generated correctly).

If you open the jsfiddle URL, then open the developer tools in your browser and look at the console output you will see a dump of the token object that is passed to stripeTokenHandler().

When you hit Submit Payment the page POSTs to https://postman-echo.com/post which will dump out your request. You'll notice the request looks something like this:

{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "stripeToken": "tok_1F07d72eZvKYlo2CqBprboVK"
  },
  "headers": {
    "x-forwarded-proto": "https",
    "host": "postman-echo.com",
    "content-length": "40",
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
    "accept-encoding": "gzip, deflate, br",
    "accept-language": "en-US,en;q=0.9",
    "cache-control": "no-cache",
    "content-type": "application/x-www-form-urlencoded",
    "cookie": "sails.sid=s%3AHyTHsNyIhRvFINR3EGiXw1Kf12oufx84.jd6rEiCaqHsrM8eOGN1x%2ByzU%2BMatjM4l5S1Ekxhxdyo",
    "origin": "https://fiddle.jshell.net",
    "pragma": "no-cache",
    "referer": "https://fiddle.jshell.net/",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36",
    "x-forwarded-port": "443"
  },
  "json": {
    "stripeToken": "tok_1F07d72eZvKYlo2CqBprboVK"
  },
  "url": "https://postman-echo.com/post"
}

The important parts are headers.content-type and json attributes. This means the stripe.js lib POSTed the form via the application/x-www-form-urlencoded MIME type, and that the stripeToken was included.

This means your issue is one/both of the following:

  1. If you are not seeing a token generated in the browser, your stripe private key is probably incorrect. I'd start out with using your stripe test private key, it looks like pk_test_xxx.
  2. Your Laravel server is not setup correctly. Lots of potential issues, would need more info, and unfortunately I've never used Laravel.

Lastly, I found a Stripe integration package for Laravel, might be worth trying: https://github.com/cartalyst/stripe-laravel

like image 141
rynop Avatar answered Oct 22 '22 14:10

rynop