Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
No-code
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support
Overview
Online payments
    Overview
    How cards work
    Quickstart
    Accept a payment
    Add funds to your balance
    Faster checkout with Link
    More payment scenarios
      Set up future payments
      Save payment details during payment
      Place a hold on a payment method
      Build a two-step confirmation experience
      Collect payment details before creating an Intent
      Finalize payments on the server
      Multiple payment method configurations on automatic payment methods
      3D Secure authentication
      Accept card payments in installments
      Card brand choice
      Supported card brands
      Currencies
      Currency conversions
      Settlement Fees
    US and Canadian cards
Products and prices
Invoicing
Subscriptions
Quotes
In-person payments
Multiparty payments
After the payment
Add payment methods
Payment Links
Stripe Checkout
Stripe Elements
About the APIs
Regulation support
Implementation guides
Testing
Payments
·
HomePaymentsOnline paymentsMore payment scenarios

Card authentication and 3D Secure

Learn about authentication to reduce fraud and meet regulatory requirements.

In October of 2022, all major card brands will stop supporting 3D Secure 1. If you want to continue using 3D Secure, adopt the Payment Intents API or Setup Intents API. This new integration:

  • Leverages benefits from Dynamic 3D Secure
  • Supports 3D Secure 2
  • Complies with Strong Customer Authentication regulation in Europe.

For extra fraud protection, 3D Secure (3DS) requires customers to complete an additional verification step with the card issuer when paying. Typically, you direct the customer to an authentication page on their bank’s website, and they enter a password associated with the card or a code sent to their phone. This process is familiar to customers through the card networks’ brand names, such as Visa Secure and Mastercard Identity Check. Watch our video for an example of an authenticated checkout flow.

The Strong Customer Authentication regulation in Europe requires the use of 3DS for card payments. 3DS is optional in other regions but you can still use it as a tool to reduce fraud.

Step 1: The customer enters their card details.

Step 2: The customer’s bank assesses the transaction and can complete 3D Secure at this step.

Step 3: If required by their bank, the customer completes an additional authentication step.

Stripe supports 3D Secure 2. Your integration runs 3D Secure 2 when supported by the customer’s bank and falls back to 3D Secure 1 otherwise.

Want to use Stripe’s 3D Secure service with other processors? Contact support.

Disputed payments and liability shift

Payments that have been successfully authenticated using 3D Secure are covered by a liability shift. Should a 3D Secure payment be disputed as fraudulent by the cardholder, the liability shifts from you to the card issuer. These types of disputes are handled internally, don’t appear in the Dashboard, and don’t result in funds being withdrawn from your Stripe account.

If a customer disputes a payment for any other reason (for example, product not received), then the standard dispute process applies. As such, you should make the appropriate decisions regarding your business and how you manage disputes if they occur, and how to avoid them completely.

Liability shift might also occur when the card network requires 3DS, but it isn’t available for the card or issuer. This can happen if the issuer’s 3DS server is down or if the issuer doesn’t support it, despite the card network requiring support. During the payment process, the cardholder isn’t prompted to complete 3DS authentication, because the card isn’t enrolled. Although the cardholder didn’t complete 3DS authentication, liability still shifts to the issuer.

Sometimes payments that are successfully authenticated using 3DS don’t experience a liability shift. This is rare and can happen, for example, if you have an excessive level of fraud on your account and are enrolled in a fraud monitoring program. There are also some industries that certain networks have exempted from liability shift—for example Visa doesn’t support liability shift with businesses engaging in wire transfer or money orders, non-financial institutions offering foreign or non-fiat currency, or stored-value card purchase or load.

Although cardholders can’t dispute payments that have been successfully authenticated using 3DS as fraudulent with an upfront financial chargeback, issuers might initiate a dispute inquiry. This type of dispute is non-financial, and is basically a request for information.

Responding to inquiries is important for any charge, but is vital when it involves a 3D-Secure-authenticated charge. Although the cardholder’s bank isn’t allowed to file an upfront financial chargeback for fraud, they can initiate a financial chargeback if the merchant doesn’t respond to the inquiry, known as a no-reply chargeback. To prevent no-reply chargebacks on 3DS charges, be sure to submit sufficient information about the charge. Include information about what was ordered, how it was delivered, and whom it was delivered to (whether it was physical or electronic goods, or services).

Controlling when to present the 3D Secure flow

Stripe triggers 3DS automatically if required by a regulatory mandate such as Strong Customer Authentication. You can also use Radar rules or the API to control when to prompt customers to complete 3DS authentication, making a determination for each user based on the desired parameters.

To track whether 3DS was attempted on a card payment, read the three_d_secure property on the card information in the Charge’s payment_method_details. Stripe populates the three_d_secure property when the customer attempts to authenticate the card—three_d_secure.succeeded indicates that authentication succeeded.

When you run 3D Secure, Stripe requires your customer to perform authentication to complete the payment if 3DS authentication is available for a card.

If a card doesn’t support 3DS or an error occurs during the authentication process, the payment proceeds normally. When this occurs, liability doesn’t generally shift to the issuer, as a successful 3DS authentication hasn’t taken place.

In a typical payment flow that triggers 3D Secure:

  1. The customer enters their payment information, which attaches to a PaymentIntent.
  2. Stripe assesses if the transaction requires 3D Secure based on Radar rules, manual requests, and other criteria.
  3. If 3D Secure is:
    • Not required–Stripe attempts the charge. If required by the bank, the customer completes an additional authentication step for the charge to succeed.
    • Required–Stripe starts the 3D Secure authentication flow by contacting the card issuer’s 3D Secure server and creating a 3D Secure source.
  4. When Stripe requests 3D Secure and the attempt is:
    • Successful–The PaymentIntent transitions to a status of requires_action. After the customer completes the 3D Secure authentication step, Stripe attempts the charge and the PaymentIntent transitions to a status of processing.
    • Unsuccessful–Stripe makes a final attempt to complete the payment without authentication. The PaymentIntent transitions to one of the following statuses, depending on the outcome of the payment: succeeded, requires_capture, or requires_payment_method.

Use Radar rules in the Dashboard

Stripe provides three default rules to dynamically request 3DS when creating or confirming a PaymentIntent or SetupIntent. You can configure these 3D Secure Radar rules in your Stripe Dashboard. The following screenshot shows these Radar rules, which request additional authentication from customers when the issuer of their card requires 3DS:

The first rule is enabled by default, but you can disable it.

If you have Radar for Fraud Teams, you can add custom 3DS rules using the syntax described in the Rules reference. Radar requests 3DS authentication for payments that match these rules. In the example below, the enabled rule requests 3DS authentication for payment attempts where the amount of the payment exceeds 500 USD and the risk level isn’t considered normal.

Custom rules for 3D Secure and liability shift

If you have Radar for Fraud Teams, you can customize your rules to allow charges to succeed and check that any on-session charges are authenticated. For example, you can do the following:

Radar ruleDescription
Block if not :is_3d_secure: and not :is_off_session:Allow recurring subscription charges (that request exemptions) to succeed. When creating payments with the API, use request_three_d_secure: any to request 3D Secure on all charges and check for a 3D Secure source.
Block if not :is_3d_secure: and not :is_off_session: and :digital_wallet: != ‘apple_pay’ and not (:digital_wallet: = ‘android_pay’ and :has_cryptogram:)Allow recurring charges on Apple Pay or Google Pay to succeed. In addition, request 3D Secure on all charges and check that any on-session charges are authenticated. To check if Stripe received a cryptogram during tokenization for Google Pay, modify the rule as shown.
Request 3D Secure if ::foo:: = ‘bar’Use Radar to request 3D Secure on all charges and check for a 3D Secure source. You can specify a custom metadata attribute for all charges that require 3D Secure. The rule checks for that condition and then requests 3D Secure. For example, you can replace ::foo:: = ‘bar’ with a value like risk_score > 65 or ::customer:trusted:: = ‘false’.
Block if ::foo:: = ‘bar’ and not :is_3d_secure:Use Radar to check if 3D Secure was requested on charges that match the condition you specified in the rule above.
Block if ::foo:: = ‘bar’ and not :is_3d_secure: and :digital_wallet: != ‘apple_pay’ and not (:digital_wallet: = 'android_pay' and :has_cryptogram:)Use Radar to request 3D Secure on all charges and check for a 3D Secure source. Modify the rule as shown to check for the custom metadata attribute that you specify on all Apple Pay or Google Pay charges, and to check if Stripe received a cryptogram during tokenization for Google Pay.

Manually request 3D Secure with the API

The default method to trigger 3DS is using Radar to dynamically request 3D Secure based on risk level and other requirements. Triggering 3DS manually is for advanced users integrating Stripe with their own fraud engine.

To trigger 3DS manually, set payment_method_options[card][request_three_d_secure] to any when creating or confirming a PaymentIntent or SetupIntent. This process is the same for one-time payments or future off-session payments. When you provide this parameter, Stripe attempts to perform 3DS and overrides any dynamic 3D Secure Radar rules on the PaymentIntent or SetupIntent.

When to provide this parameter depends on when your fraud engine detects risk. For example, if your fraud engine only inspects card details, you know whether to request 3DS before you create the PaymentIntent or SetupIntent. If your fraud engine inspects both card and transaction details, provide the parameter during confirmation—when you have more information. Then pass the resulting PaymentIntent or SetupIntent to your client to complete the process.

Explore the request_three_d_secure parameter’s usage for each case in the API reference:

  • Create a PaymentIntent
  • Confirm a PaymentIntent
  • Create a SetupIntent
  • Confirm a SetupIntent

When you set request_three_d_secure to any, Stripe requires your customer to perform authentication to complete the payment successfully if 3DS authentication is available for a card. If it’s not available for the given card, the payment proceeds normally.

Stripe’s SCA rules run automatically, regardless of whether or not you manually request 3DS. Any 3DS prompts from you are additional and not required for SCA.

Displaying the 3D Secure Flow

Stripe automatically displays the authentication UI in a pop-up modal when calling confirmCardPayment and handleCardAction. You can also redirect to the bank’s website or use an iframe.

Stripe.js collects basic device information during 3D Secure 2 authentication and sends it to the issuing bank for their risk analysis.

Redirect to the bank website

To redirect your customer to the 3DS authentication page, pass a return_url to the PaymentIntent when confirming on the server or on the client. You can also set return_url when creating the PaymentIntent.

After confirmation, if a PaymentIntent has a requires_action status, inspect the PaymentIntent’s next_action. If it contains redirect_to_url, that means 3DS is required.

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

In the browser, redirect the customer to the url in the redirect_to_url hash to complete authentication.

var 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, the redirect sends them back to the return_url you specified when you created or confirmed 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 purchase.

Display in an iframe

You can’t customize the authentication UI on the web to match your website’s design—the bank that issued the card controls the fonts and colors.

However, you can choose how and where to show the 3D Secure UI. 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.

1 Confirm the PaymentIntent Server-side

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 how to display 3D Secure, provide a return_url, which is where the 3D Secure <iframe> is redirected when 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’re confirming from the frontend, use the confirmCardPayment method in Stripe.js. For example, if you’re gathering card information using Stripe Elements:

stripe.confirmCardPayment( '{{PAYMENT_INTENT_CLIENT_SECRET}}', { payment_method: {card: cardElement}, return_url: 'https://example.com/return_url' }, // Disable the default next action handling. {handleActions: false} ).then(function(result) { // Handle result.error or result.paymentIntent // More details in Step 2. });

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

Command Line
curl https://api.stripe.com/v1/payment_intents/{{PAYMENT_INTENT_ID}}/confirm \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d return_url="https://example.com/return_url"

2 Check the PaymentIntent status Server-side

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

StatusDescription
requires_payment_methodThe 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_captureThe request completed without authentication. You can continue to capture the funds.
requires_actionAn additional step like 3D Secure is required to complete the payment. Ask the customer to return to your application to complete payment.
succeededThe payment completed, creating a Charge with 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.

3 Render the 3D Secure iframe Client-side

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.

The sandbox attribute cannot be used on the 3D Secure iframe. In live mode, some content inside this iframe is controlled by the card issuer. Some issuers’ implementations will fail if sandboxed and the payment will never succeed.

4 Handle the redirect Client-side

After the customer completes 3D Secure, the iframe redirects 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 the payment succeeded or requires further action from your customer.

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 is requires_payment_method. If the payment completed successfully, the status is succeeded. If you use separate authorize and capture, the status is 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 the 3D Secure flow

Use a Stripe test card with any CVC, postal code, and future expiration date to trigger 3DS authentication challenge flows while in test mode.

When you build an integration with your test API keys, the authentication process displays a mock authentication page. On that page, you can either authorize or cancel the payment. Authorizing the payment simulates successful authentication and redirects you to the specified return URL. Clicking the Failure button simulates an unsuccessful attempt at authentication.

Number3DS usageDescription
RequiredThe payment must complete 3DS2 authentication to be successful. By default, your Radar rules request 3DS authentication for this card.
RequiredThe payment must complete 3DS authentication to be successful. By default, your Radar rules request 3DS authentication for this card.
Required3DS authentication is required, but payments will be declined with a card_declined failure code after authentication. By default, your Radar rules request 3DS authentication for this card.
Supported3DS authentication can still be performed, but isn’t required. By default, your Radar rules won’t request 3DS authentication for this card.
SupportedThis card supports 3DS, but it isn’t enrolled in 3DS. This means that if your Radar rules request 3DS, the customer won’t go through additional authentication. By default, your Radar rules won’t request 3DS authentication for this card.
Not supportedThis card doesn’t support 3DS and you can’t invoke it. The PaymentIntent proceeds without performing authentication.

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

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

Was this page helpful?
Questions? Contact us.
Watch our developer tutorials.
Check out our product changelog.
Powered by Markdoc
You can unsubscribe at any time. Read our privacy policy.
On this page
Disputed payments and liability shift
Controlling when to present the 3D Secure flow
Manually request 3D Secure with the API
Displaying the 3D Secure Flow
Testing the 3D Secure flow
Stripe Shell
Test mode
Welcome to the Stripe Shell! Stripe Shell is a browser-based shell with the Stripe CLI pre-installed. Login to your Stripe account and press Control + Backtick on your keyboard to start managing your Stripe resources in test mode. - View supported Stripe commands: - Find webhook events: - Listen for webhook events: - Call Stripe APIs: stripe [api resource] [operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$