5

Here is my HTML form and use the stripe latest PaymentIntent API. My problem is i am not getting the 3D secure authorization pop up. Can anyone please help me to guide the thins making me wrong? I have tried to follow the stripe docs (https://stripe.com/docs/payments/payment-intents/web#handling-next-actions) but it's totally confusing.

<script src='https://js.stripe.com/v3/' type='text/javascript'></script>
<form action="process_payment.php" method="post" id="payment-form">
    <div class="form-row">
        <label for="card-element">
            Credit or debit card
        </label>
        <div id="card-element"><!-- Your form goes here --></div>
    </div>
    <!-- Used to display form errors -->
    <div id="card-errors" role="alert"></div>
    <button class="atbdp_pay_btn" type="submit">Pay</button>
</form>

Javascript

document.addEventListener("DOMContentLoaded", function(event) {
        var stripe = Stripe('pk_test_xxxxxxxxxx'); // test publishable API key
        var elements = stripe.elements();

        var card = elements.create('card');
        // Add an instance of the card UI component into the `card-element` <div>
        card.mount('#card-element');

        // Handle events and errors
        card.addEventListener('change', function(event) {
            var displayError = document.getElementById('card-errors');
            if (event.error) {
                displayError.textContent = event.error.message;
            } else {
                displayError.textContent = '';
            }
        });

        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();
        }

        function createToken() {
            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);
                }
            });
        };

        // Create a token when the form is submitted.
        var form = document.getElementById('payment-form');
        form.addEventListener('submit', function(e) {
            e.preventDefault();
            createToken();
        });

    });

Finally handle the response

require_once 'init.php';
\Stripe\Stripe::setApiKey( 'sk_test_xxxxxxxx' );
$stripeToken = $_POST['stripeToken']; // stripe will handle the sanitization
$error_msg = '';
try {
    $intent = \Stripe\PaymentIntent::create([
        'payment_method_data' => [
            'type' => 'card',
            'card' => ['token' => $stripeToken],
        ],
        'amount' => 19 * 100,
        'currency' => 'usd',
        'confirmation_method' => 'manual',
        'confirm' => true,
    ]);
    $result = generatePaymentResponse($intent);
}catch (\Stripe\Card $exception){

}

function generatePaymentResponse($intent) {
    if ($intent->status == 'requires_source_action' &&
        $intent->next_action->type == 'use_stripe_sdk') {
        # Tell the client to handle the action
        echo json_encode([
            'requires_action' => true,
            'payment_intent_client_secret' => $intent->client_secret
        ]);
    } else if ($intent->status == 'succeeded') {
        # The payment didn’t need any additional actions and completed!
        # Handle post-payment fulfillment
        echo json_encode([
            'success' => true
        ]);
    } else {
        # Invalid status
        http_response_code(500);
        echo json_encode(['error' => 'Invalid PaymentIntent status']);
    }
}

The response is

"requires_action": true,
  "payment_intent_client_secret": "pi_1FIowAIUv6RpAcZVcd9txP1g_secret_M0byttxAd4ZFB4NxLgsanaZZS"
Machavity
  • 30,841
  • 27
  • 92
  • 100
Rafiq
  • 86
  • 1
  • 8
  • 1
    2 things to check. Did you enable 3D secure in Stripe interface? Test account. And did you use the card numbers used for testing 3D secure? There is one for each scenario you want to test. https://stripe.com/docs/testing – Mig Sep 15 '19 at 04:57
  • Yes, I do use 3D secure testing card, but I have no idea about '3D secure in Stripe interface'. :) – Rafiq Sep 15 '19 at 05:14
  • Your frontend code doesn't do any 3D Secure handling though. stripe.createToken will not do any 3D Secure. As your PaymentIntent says, it is in the `requires_action` status. The link you linked _is_ what you have to do : https://stripe.com/docs/payments/payment-intents/web-manual#handling-next-actions calling `handleCardAction` on the client side is what makes the 3D Secure window appear. – karllekko Sep 15 '19 at 11:42
  • @karllekko Thanks for your tricks. I have found the solution [here](https://stripe.com/docs/payments/payment-intents/web) – Rafiq Sep 16 '19 at 03:47
  • Yes each time I use stripe again, the process is slightly different. It is good because it makes things easier, but then it makes it hard to find answers outside of their documentation because it is often outdated. – Mig Sep 16 '19 at 06:30
  • Still i'm not getting the popup. Can you please provide the full updated code. – Sandra Sep 16 '19 at 09:00
  • 1
    @Sandra here is the complete [code](https://github.com/aazztech/simple-stripe-payment.git) – Rafiq Sep 17 '19 at 09:24

1 Answers1

4

You are using stripe.createToken which does not support 3ds authentication.
You need to migrate your client side code to stripe.createPaymentMethod which does support it.

There's a useful migration guide in the stripe docs, you can follow it here

Nir Levy
  • 12,750
  • 3
  • 21
  • 38