Supporting 3D Secure Authentication on Web

    Learn how to perform additional authentication with your Checkout or Stripe.js integration.

    Stripe’s new Checkout and the Payment Intents API natively support 3D Secure and trigger it automatically if required by a regulatory mandate such as Strong Customer Authentication. You can also use Radar rules to control when customers are prompted to complete 3D Secure authentication, making a determination for each user based on the desired parameters.

    On the web, you have a few options for displaying 3D Secure:

    To track whether 3D Secure was attempted on a card payment, you can read the three_d_secure property on the card information in the charge’s payment_method_details. The property is populated when 3D Secure is attempted on a charge, and three_d_secure.succeeded indicates whether 3DS authentication was successful.

    Manually handling 3D Secure authentication with redirect

    A common action of interest is authenticating the customer’s payment with 3D Secure, as required by upcoming Strong Customer Authentication rules. There are several ways to handle this in an integration. The recommended way is to use the handleCardPayment, handleCardAction, or handleCardSetup functions in Stripe.js, which assumes responsibility for ushering customers through that process and any other actions that may be required.

    To handle 3D Secure authentication manually, you can redirect the customer. This approach is used when you manually confirm the PaymentIntent and provide a return_url destination to indicate where the customer should be sent once authentication is complete. Manual PaymentIntent confirmation can be performed on the server or on the client with Stripe.js.

    After confirmation, if the PaymentIntent has a status of requires_action, inspect the PaymentIntent’s next_action, determine if it is redirect_to_url, and redirect the customer to complete authentication. When applicable, the PaymentIntent’s next_action is populated with an object that has the following shape:

    next_action: {
        type: 'redirect_to_url',
        redirect_to_url: {
          url: 'https://hooks.stripe.com/...',
          return_url: 'https://mysite.com'
        }
    }
    

    Use the following code in the browser to redirect the customer to the address provided by the next_action property:

    var action = intent.next_action;
    if (action && action.type === 'redirect_to_url') {
      window.location = action.redirect_to_url.url;
    }
    const action = intent.next_action;
    if (action && action.type === 'redirect_to_url') {
      window.location = action.redirect_to_url.url;
    }

    When the customer finishes the authentication process, they are sent back to the destination that you specified with the return_url property when you created the PaymentIntent. The redirect also adds payment_intent and payment_intent_client_secret URL query parameters that your application can use to identify the PaymentIntent associated with the customer’s purchase.

    Customizing the 3D Secure UI

    In the 3D Secure protocol, the bank that issued the card carries out authentication and controls the fonts and colors of the experience. You cannot make the authentication UI itself match your website’s design.

    However, you can choose how and where the 3D Secure UI is shown. Most merchants show it in a modal dialog above their payment page. If you have your own modal component, you can place the 3D Secure frame inside of it. You can also show the authentication content inline with your payment form. You need to embed the 3D Secure authentication UI into your payment flow as an <iframe> to a url provided by Stripe.

    1. Confirm the PaymentIntent
    2. Check the PaymentIntent status
    3. Render the 3D Secure iframe
    4. Handle the redirect

    Step 1: Confirm the PaymentIntent

    When your customer is ready to complete their purchase, you confirm the PaymentIntent to begin the process of collecting their payment.

    If you want to control the way in which 3D Secure is displayed, you will need to provide a return_url, which is where the 3D Secure <iframe> will be redirected once authentication is complete. If your site uses a content security policy, check that iframes from https://js.stripe.com, https://hooks.stripe.com, and the origin of the URL you passed to return_url are allowed.

    If you are confirming from the frontend, use the confirmPaymentIntent method in Stripe.js. For example, if your are gathering card information using Stripe Elements:

    stripe.confirmPaymentIntent(
      '{{PAYMENT_INTENT_CLIENT_SECRET}}',
      cardElement,
      {
        return_url: 'https://example.com/return_url'
      }
    ).then(function(result) {
      // Handle result.error or result.paymentIntent
      // More details in Step 2.
    });
    

    If you are confirming from your backend, be sure to provide a return_url. Depending on your integration, you may want to pass other information to confirm as well.

    curl https://api.stripe.com/v1/payment_intents/{{PAYMENT_INTENT_ID}}/confirm \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
    -d return_url="https://example.com/return_url"
    intent = Stripe::PaymentIntent.confirm(
      '{{PAYMENT_INTENT_ID}}',
      {
        return_url: 'https://example.com/return_url'
      }
    )
    
    intent = stripe.PaymentIntent.confirm(
      '{{PAYMENT_INTENT_ID}}',
      return_url='https://example.com/return_url'
    )
    
    $intent = \Stripe\PaymentIntent::retrieve('{{PAYMENT_INTENT_ID}}');
    $intent->confirm([
        'return_url' => 'https://example.com/return_url',
    ]);
    
    PaymentIntent intent = PaymentIntent.retrieve("{{PAYMENT_INTENT_ID}}");
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("return_url", "https://example.com/return_url");
    intent.confirm(params);
    
    (async () => {
      let intent = await stripe.paymentIntents.confirm(
        '{{PAYMENT_INTENT_ID}}',
        {
          return_url: 'https://example.com/return_url'
        }
      );
    })()
    
    params := &stripe.PaymentIntentConfirmParams{
      ReturnUrl: stripe.String("https://example.com/return_url"),
    }
    intent, err := paymentintent.Confirm("{{PAYMENT_INTENT_ID}}", params)
    
    var service = new PaymentIntentService();
    var options = new PaymentIntentConfirmOptions
    {
      ReturnUrl = "https://example.com/return_url",
    };
    var intent = service.Confirm("{{PAYMENT_INTENT_ID}}", options);
    

    Step 2: Check the PaymentIntent status

    Next, inspect the status property of the confirmed PaymentIntent to determine if the payment completed successfully. The following list describes possible status values and their significance:

    Status Description
    requires_payment_method The request failed with a 402 HTTP status code, meaning that the payment was unsuccessful. Check the last_payment_error property and attempt to try again, collecting new payment information from the customer if necessary.
    requires_action An additional step like 3D Secure is required to complete the payment. Notify the customer to return to your application to complete payment.
    succeeded The payment completed and resulted in the creation of a charge using the supplied payment method. No further steps are required.

    Note that on versions of the API before 2019-02-11, requires_payment_method appears as requires_source and requires_action appears as requires_source_action.

    Step 3: Render the 3D Secure iframe

    When the value of the status property is requires_action, some additional step is required before payment can be processed. For a card payment requiring 3D Secure, the PaymentIntent’s status will be requires_action and its next_action property will be redirect_to_url. The redirect_to_url payload contains a URL that you should open in an iframe to display 3D Secure:

    var iframe = document.createElement('iframe');
    iframe.src = paymentIntent.next_action.redirect_to_url.url;
    iframe.width = 600;
    iframe.height = 400;
    yourContainer.appendChild(iframe);

    For 3D Secure 2, card issuers are required to support showing the 3D Secure content at sizes of 250x400, 390x400, 500x600, 600x400, and full screen (dimensions are width by height). The 3D Secure UI may be better if you open the iframe at exactly one of those sizes.

    Step 4: Handle the redirect

    After the customer completes 3D Secure, the iframe will be redirected to the return_url you provided when confirming the PaymentIntent. That page should postMessage to your top-level page to inform it that 3D Secure authentication is complete. Your top-level page should then determine whether payment was successful or if your customer needs to take further action.

    For example, you might have your return_url page execute:

    window.top.postMessage('3DS-authentication-complete');

    Your top payment page should be listening for this postMessage to know when authentication has finished. You should then retrieve the updated PaymentIntent and check on the status of the payment. If the authentication failed, the PaymentIntent’s status will be requires_payment_method. If the payment completed successfully, it will be succeeded. If you use separate authorize and capture, the status will be requires_capture instead.

    function on3DSComplete() {
      // Hide the 3DS UI
      yourContainer.remove();
    
      // Check the PaymentIntent
      stripe.retrievePaymentIntent('{{PAYMENT_INTENT_CLIENT_SECRET}}')
        .then(function(result) {
          if (result.error) {
            // PaymentIntent client secret was invalid
          } else {
            if (result.paymentIntent.status === 'succeeded') {
              // Show your customer that the payment has succeeded
            } else if (result.paymentIntent.status === 'requires_payment_method') {
              // Authentication failed, prompt the customer to enter another payment method
            }
          }
        });
    }
    
    window.addEventListener('message', function(ev) {
      if (ev.data === '3DS-authentication-complete') {
        on3DSComplete();
      }
    }, false);

    Testing 3D Secure payments

    Not all cards support 3D Secure or require the customer be redirected to their card issuer’s authentication page. Use the following card information to fully test 3D Secure payments.

    Number 3D Secure usage Description
    4000000000003220 Required 3D Secure 2 authentication must be completed for the payment to be successful. By default, your Radar rules will request 3D Secure authentication for this card.
    4000000000003063 Required 3D Secure authentication must be completed for the payment to be successful. By default, your Radar rules will request 3D Secure authentication for this card.
    4000008400001629 Required 3D Secure authentication is required, but payments will be declined with a card_declined failure code after authentication. By default, your Radar rules will request 3D Secure authentication for this card.
    4000000000003055 Supported 3D Secure authentication may still be performed, but is not required. By default, your Radar rules will not request 3D Secure authentication for this card.
    4242424242424242 Supported 3D Secure is supported for this card, but this card is not enrolled in 3D Secure. This means that if 3D Secure is requested by your Radar rules, the customer will not go through additional authentication. By default, your Radar rules will not request 3D Secure authentication for this card.
    378282246310005 Not supported 3D Secure is not supported on this card and cannot be invoked. The PaymentIntent will proceed without performing authentication.
    Token 3D Secure usage Description
    tok_threeDSecure2Required Required 3D Secure 2 authentication must be completed for the payment to be successful. By default, your Radar rules will request 3D Secure authentication for this card.
    tok_threeDSecureRequired Required 3D Secure authentication must be completed for the payment to be successful. By default, your Radar rules will request 3D Secure authentication for this card.
    tok_threeDSecureRequiredChargeDeclined Required 3D Secure authentication is required, but payments will be declined with a card_declined failure code after authentication. By default, your Radar rules will request 3D Secure authentication for this card.
    tok_threeDSecureOptional Supported 3D Secure authentication may still be performed, but is not required. By default, your Radar rules will not request 3D Secure authentication for this card.
    tok_visa Supported 3D Secure is supported for this card, but this card is not enrolled in 3D Secure. This means that if 3D Secure is requested by your Radar rules, the customer will not go through additional authentication. By default, your Radar rules will not request 3D Secure authentication for this card.
    tok_amex_threeDSecureNotSupported Not supported 3D Secure is not supported on this card and cannot be invoked. The PaymentIntent will proceed without performing authentication.
    Payment Method 3D Secure usage Description
    pm_card_threeDSecure2Required Required 3D Secure 2 authentication must be completed for the payment to be successful. By default, your Radar rules will request 3D Secure authentication for this card.
    pm_card_threeDSecureRequired Required 3D Secure authentication must be completed for the payment to be successful. By default, your Radar rules will request 3D Secure authentication for this card.
    pm_card_threeDSecureRequiredChargeDeclined Required 3D Secure authentication is required, but payments will be declined with a card_declined failure code after authentication. By default, your Radar rules will request 3D Secure authentication for this card.
    pm_card_threeDSecureOptional Supported 3D Secure authentication may still be performed, but is not required. By default, your Radar rules will not request 3D Secure authentication for this card.
    pm_card_visa Supported 3D Secure is supported for this card, but this card is not enrolled in 3D Secure. This means that if 3D Secure is requested by your Radar rules, the customer will not go through additional authentication. By default, your Radar rules will not request 3D Secure authentication for this card.
    pm_card_amex_threeDSecureNotSupported Not supported 3D Secure is not supported on this card and cannot be invoked. The PaymentIntent will proceed without performing authentication.

    All other Visa and Mastercard test cards do not require authentication from the customer’s card issuer.

    Testing the authentication process

    When you build an integration with your test API keys, the authentication process displays a modal with information about the API request. In that dialog, you can either authorize or cancel the payment. Authorizing the payment simulates successful authentication and redirects you to the specified return URL. Clicking on the Failure button simulates an unsuccessful attempt at authentication.

    You can write custom Radar rules in test mode to trigger authentication on test cards. You can learn more about testing your Radar rules in our Radar documentation.

    Next steps

    For more information, refer to the following documentation:

    Was this page helpful?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page