Plain Dev Blog
← Back to all posts

3Ds authentication with Stripe

·

3Ds authentication with Stripe

I’ve been working with Stripe for a good few years now and I thought that I’ve seen it all especially when it comes to cards and elements implementation.

Well, I haven’t just recently I’ve stumbled upon the cases of these types of authentication with Stripe elements.

“3D Secure (3DS) is an authentication protocol that adds an additional security layer to card transactions. By verifying that the person making a purchase is the legitimate cardholder, 3DS helps protect both your business and your customers from fraudulent activity.”

Having an implementation of Stripe Elements I thought I’ve covered those cases, but that wasn’t it, when I tried with a few of the stripes test cards which requires such confirmation…well it did not went good…

After some further research I’ve found out that in order to prompt such confirmation an additional code should be added in my case to the functionality where I was saving card’s data.

Previously I was creating new payment method:

stripe.createPaymentMethod({
   type: 'card',
   card: cardElement,
   billing_details: {
      name: cardHolderName
   }
})

If the request is successful taking the payment_method from the response and attaching it, to the customer and that was about it.

But now I needed to confirm the payment method while creating it, so now I need to use:

stripe.confirmCardSetup(clientSecret, {
    payment_method: {
      card: cardElement,
      billing_details: {name: cardHolderName},
    },
})

Now it uses confirmCardSetup method to confirm the card if required and then to create the payment method from it.

client_secret is coming from a SetupIntent object which you can create in two ways:

Creating it directly from a user

$intent = $user->createSetupIntent([
    'payment_method_types' => ['card', 'cashapp'],
]);

or you call the Stripe API directly:

$stripe = new StripeClient(<your-stripe-secret-here>);

$intent = $stripe->setupIntents->create([
  'payment_method_types' => [
      'card', 'cashapp'
   ]
]);

in both cases you will receive a SetupIntent object:

{
  "id": "seti_1Mm8s8LkdIwHu7ix0OXBfTRG",
  "object": "setup_intent",
  "application": null,
  "cancellation_reason": null,
  "client_secret": "seti_1Mm8s8LkdIwHu7ix0OXBfTRG_secret_NXDICkPqPeiBTAFqWmkbff09lRmSVXe",
  "created": 1678942624,
  "customer": null,
  "description": null,
  "flow_directions": null,
  "last_setup_error": null,
  "latest_attempt": null,
  "livemode": false,
  "mandate": null,
  "metadata": {},
  "next_action": null,
  "on_behalf_of": null,
  "payment_method": null,
  "payment_method_options": {
    "card": {
      "mandate_options": null,
      "network": null,
      "request_three_d_secure": "automatic"
    }
  },
  "payment_method_types": [
    "card"
  ],
  "single_use_mandate": null,
  "status": "requires_payment_method",
  "usage": "off_session"
}

It provides the same information with the addition of a pop-up(in testing environment):

which emulates the 3DS confirmation.

A few words on the cards with which you can test with

You can find them here , let’s dig in:

  • 4000 0025 0000 3155 — requires confirmation for of-session payments unless you set it up all on-session payments require confirmation

  • 4000 0027 6000 3184 — always require confirmation for off-session and on-session payments

  • 4000 0038 0000 0446 — already set up for of-session payments one-time payments and on-session payment require confirmation

  • 4000 0082 6000 3178 — require confirmation but fails with insufficient-funds always

I had some mishaps with them cards (always read the description carefully before start testing!) in the end I had more success with the third one because I had more of-session payments

On session and of session payments

From what I was told by one of Stripe’s support agents, on session payments are those when the client is in your checkout flow of session payments are when payments are initiated automatically.

  • on-session — Subscription Creation, Update, Downgrade from your website interface

  • of-session — the payments for subscription renewal

Better and more detailed explanation about it you can read here

So that was my take on the topic, one more thing: There is always more things to learn for any topic

Conclusion

The 3DS auth is strong way of protecting people with payments in internet, more commonly used by bank institutions across the EU it's still something worth your while.

Share this post