Learn how to test 3D Secure payments in Stripe, set up your test environment, use test cards, and handle authentication scenarios to ensure secure, compliant payments.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to Test 3D Secure Payments in Stripe
Introduction
Testing 3D Secure (3DS) payments in Stripe is essential for ensuring your integration works correctly before processing real transactions. 3D Secure adds an additional authentication layer for card payments, helping to reduce fraud and comply with regulations like Strong Customer Authentication (SCA) in Europe. This tutorial will guide you through the entire process of setting up and testing 3D Secure payments in Stripe's test environment.
Step 1: Set Up a Stripe Test Account
Before testing 3D Secure payments, you need a Stripe test account:
// Example of accessing your API keys
// Dashboard → Developers → API keys
const stripe = require('stripe')('sk_test_YourTestSecretKey');
Step 2: Install and Configure the Stripe Library
Depending on your tech stack, install the appropriate Stripe library:
For Node.js:
npm install stripe
For PHP:
composer require stripe/stripe-php
For Python:
pip install stripe
Step 3: Implement Stripe Elements for Card Collection
Stripe Elements provides ready-made UI components for collecting card information securely:
Stripe 3D Secure Test
Step 4: Create a Payment Intent with 3DS Support
Payment Intents are Stripe's API for handling complex payment flows, including 3D Secure:
// Server-side code (Node.js example)
const stripe = require('stripe')('sk_test_YourTestSecretKey');
async function createPaymentIntent() {
try {
const paymentIntent = await stripe.paymentIntents.create({
amount: 1999, // Amount in cents
currency: 'usd',
payment_method_types: ['card'],
// Request 3D Secure authentication
setup_future_usage: 'off\_session',
// Optional: Force 3D Secure for testing
// automatic_payment_methods: {
// enabled: true,
// }
});
return paymentIntent;
} catch (error) {
console.error('Error creating payment intent:', error);
throw error;
}
}
Step 5: Confirm the Payment and Handle 3D Secure Authentication
Add the confirmation logic to your client-side code:
// Client-side JavaScript
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
event.preventDefault();
// Disable the submit button to prevent repeated clicks
const submitButton = form.querySelector('button');
submitButton.disabled = true;
// Get the PaymentIntent client secret from your server
const response = await fetch('/create-payment-intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 1999,
currency: 'usd',
}),
});
const data = await response.json();
const { clientSecret } = data;
// Confirm the payment with the card Element
const result = await stripe.confirmCardPayment(clientSecret, {
payment\_method: {
card: card,
billing\_details: {
name: 'Test Customer',
},
},
});
if (result.error) {
// Show error to your customer
const errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
submitButton.disabled = false;
} else {
// The payment is processed or requires 3D Secure authentication
if (result.paymentIntent.status === 'succeeded') {
// Payment succeeded
window.location.href = '/success';
} else if (result.paymentIntent.status === 'requires\_action') {
// 3D Secure authentication is required
const { error, paymentIntent } = await stripe.handleCardAction(
result.paymentIntent.client\_secret
);
if (error) {
// Authentication failed
const errorElement = document.getElementById('card-errors');
errorElement.textContent = error.message;
} else if (paymentIntent.status === 'succeeded') {
// Authentication succeeded
window.location.href = '/success';
}
}
}
submitButton.disabled = false;
});
Step 6: Use Stripe Test Cards for 3D Secure Testing
Stripe provides specific test cards for 3D Secure testing:
// 3D Secure Authentication Required and Succeeds
4000000000003220
// 3D Secure Authentication Required and Fails
4000008400001629
// 3D Secure Required but Not Supported by Issuer
4000000000003063
// 3D Secure Not Required
4242424242424242
For each of these cards, you can use:
Step 7: Test the Complete 3D Secure Flow
Now, you'll want to test the complete flow:
Here's server-side code to handle the webhook for the completed payment:
// Node.js with Express example
const express = require('express');
const app = express();
const stripe = require('stripe')('sk_test_YourTestSecretKey');
app.post('/webhook', express.raw({type: 'application/json'}), async (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(
req.body,
sig,
'whsec\_YourWebhookSecret'
);
} catch (err) {
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the event
if (event.type === 'payment\_intent.succeeded') {
const paymentIntent = event.data.object;
// Payment was successful
console.log('PaymentIntent was successful!');
} else if (event.type === 'payment_intent.payment_failed') {
const paymentIntent = event.data.object;
console.log('Payment failed:', paymentIntent.last_payment_error?.message);
}
// Return a 200 response to acknowledge receipt of the event
res.send();
});
app.listen(3000, () => console.log('Running on port 3000'));
Step 8: Test Different 3D Secure Scenarios
It's important to test various 3D Secure scenarios to ensure your application handles all cases correctly:
// Test function to try different 3D Secure scenarios
async function test3DSecureScenarios() {
const testCases = [
{
description: "3D Secure Required & Succeeds",
cardNumber: "4000000000003220",
expectedOutcome: "Payment should complete successfully after 3DS authentication"
},
{
description: "3D Secure Required & Fails",
cardNumber: "4000008400001629",
expectedOutcome: "Payment should fail after 3DS authentication"
},
{
description: "3D Secure Required but Not Supported",
cardNumber: "4000000000003063",
expectedOutcome: "Payment should fail as 3DS is required but not supported"
},
{
description: "3D Secure Not Required",
cardNumber: "4242424242424242",
expectedOutcome: "Payment should complete successfully without 3DS"
}
];
console.log("Starting 3D Secure test scenarios...");
for (const testCase of testCases) {
console.log(`\nTesting: ${testCase.description}`);
console.log(`Card: ${testCase.cardNumber}`);
console.log(`Expected outcome: ${testCase.expectedOutcome}`);
// Here you would programmatically test each scenario
// In a real implementation, you might use a testing framework
// or simulate user input in a browser automation tool
}
}
Step 9: Monitor and Debug 3D Secure Payments
Use Stripe's dashboard and logs to monitor and debug your 3D Secure test payments:
// Node.js example of retrieving and inspecting a PaymentIntent
async function checkPaymentStatus(paymentIntentId) {
try {
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
console.log('Payment Intent Status:', paymentIntent.status);
console.log('Last Payment Error:', paymentIntent.last_payment_error);
// Check if 3D Secure was used
const charges = paymentIntent.charges.data;
if (charges.length > 0) {
console.log('3D Secure used:', charges[0].payment_method_details.card.three_d_secure !== null);
console.log('3D Secure result:', charges[0].payment_method_details.card.three_d_secure?.result);
}
return paymentIntent;
} catch (error) {
console.error('Error retrieving payment intent:', error);
throw error;
}
}
Step 10: Implement Error Handling for 3D Secure Failures
Proper error handling is crucial for a good user experience:
// Client-side error handling for 3D Secure
function handle3DSecureError(error) {
const errorMessages = {
'authentication\_rejected': 'Your bank declined the authentication. Please try another payment method.',
'not\_enrolled': 'Your card does not support 3D Secure. Please contact your bank or try another card.',
'timeout': 'The authentication timed out. Please try again.',
'processing\_error': 'An error occurred while processing the authentication. Please try again.'
};
const errorElement = document.getElementById('card-errors');
const errorType = error.code || 'processing\_error';
errorElement.textContent = errorMessages[errorType] || error.message || 'An unexpected error occurred.';
// Log the error for debugging (in development only)
console.error('3D Secure Error:', error);
// Enable the payment button again
document.querySelector('button[type="submit"]').disabled = false;
}
Conclusion
Testing 3D Secure payments in Stripe is a crucial step in ensuring your payment process is robust and compliant with security standards. By following this guide, you should be able to implement and test various 3D Secure scenarios before moving to a production environment. Remember to use Stripe's test cards and the test environment for all your testing needs, and only switch to the live environment when you're confident your integration works correctly.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.