Step-by-step integration
This guide walks you through 3D Secure verification for Braintree transactions. It covers the client-side flow, where your checkout page collects and verifies the card, and the server-side flow, where your server performs the lookup and challenge steps.
Integrate 3D Secure from the client side
To verify a card from the client side, generate a client token, build a threeDSecureParameters object, then call verifyCard using either the default UI or Hosted Fields.
Generate a client token
Before you can initialize the JavaScript SDK, you need to generate a client token. Generate the client_token on your server, and make sure it's accessible from the JavaScript in your checkout page.
If you want to use a merchant account ID other than your default, specify the merchant_account_id when you generate the client token. The merchant account ID used to create the client token must match the merchant account ID used to create the subsequent transaction or the merchant account ID used for verification.
Verify a card using 3D Secure
To use 3D Secure, create an object with relevant customer and transaction data to minimize the need for issuing banks to present authentication challenges to customers.
Include as many of the following fields as possible. The full list of fields is described in the SDK documentation.
- JavaScript
const threeDSecureParameters = {
amount: '500.00',
email: 'test@example.com',
billingAddress: {
givenName: 'Jill', // ASCII-printable characters required, otherwise throws a validation error
surname: 'Doe', // ASCII-printable characters required, otherwise throws a validation error
phoneNumber: '8101234567',
streetAddress: '555 Smith St.',
extendedAddress: '#5',
locality: 'Oakland',
region: 'CA', // ISO-3166-2 code
postalCode: '12345',
countryCodeAlpha2: 'US'
},
collectDeviceData: true,
additionalInformation: {
workPhoneNumber: '8101234567',
shippingGivenName: 'Jill',
shippingSurname: 'Doe',
shippingPhone: '8101234567',
shippingAddress: {
streetAddress: '555 Smith St.',
extendedAddress: '#5',
locality: 'Oakland',
region: 'CA', // ISO-3166-2 code
postalCode: '12345',
countryCodeAlpha2: 'US'
}
},
};You can submit additional device settings to 3D Secure. Submitting this data may reduce lookup failures or authentication challenges for customers. Set the collectDeviceData option to true to turn on collection of additional device data.
Verify a card with Hosted Fields
To use 3D Secure with Hosted Fields, include the client, three-d-secure, and hosted-fields scripts:
- HTML
<script src="https://js.braintreegateway.com/web/4.0.0-alpha.0/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/4.0.0-alpha.0/js/three-d-secure.min.js"></script>
<script src="https://js.braintreegateway.com/web/4.0.0-alpha.0/js/hosted-fields.min.js"></script>The threeDSecureParameters object must include the following fields:
amountnoncebin
- JavaScript
const threeDSecureParameters = {
amount: '500.00',
nonce: NONCE-FROM-INTEGRATION, // Example: hostedFieldsTokenizationPayload.nonce
bin: BIN-FROM-INTEGRATION, // Example: hostedFieldsTokenizationPayload.details.bin
// Pass other 3D Secure parameters here
};To verify vaulted cards, first generate the nonce on the server, then pass it in the threeDSecureParameters.
Handle the lookup response
Be sure to implement the onLookupComplete callback. Braintree invokes it after it receives the 3D Secure lookup response, before initializing the challenge and completing the flow.
- JavaScript
const threeDSecureParameters = {
// Pass 3D Secure parameters here
onLookupComplete: function (data, next) {
// Use 'data' here, then call 'next()'
next();
}
};Specify challengeDisplay in your options object when you call threeDSecure.create() to manage the challenge the customer sees. See the examples below for valid values: modal and inline-iframe.
- Async/Await
let threeDSecure;
async function initializeThreeDSecure() {
try {
const clientInstance = await braintree.client.create({
// Use the generated client token to instantiate the Braintree client.
authorization: 'CLIENT-TOKEN-FROM-SERVER'
});
const threeDSecureInstance = await braintree.threeDSecure.create({
challengeDisplay: 'inline-iframe',
client: clientInstance,
});
threeDSecure = threeDSecureInstance;
} catch (err) {
// Handle component creation error
}
}After this call succeeds, the threeDSecure variable holds a ready-to-use 3D Secure instance.
After you create the 3D Secure client, verify cards by passing the threeDSecureParameters object into verifyCard(). This call may challenge the cardholder to authenticate if the card is enrolled in a 3D Secure program, such as Verified by Visa, and the cardholder's issuing bank decides to challenge.
- Async/Await
async function verifyCard() {
try {
const response = await threeDSecure.verifyCard(threeDSecureParameters);
// Send response.nonce to your server for use in your integration
// The 3D Secure Authentication ID can be found
// at response.threeDSecureInfo.threeDSecureAuthenticationId
} catch (error) {
// Handle error
}
}A successful call returns a response object with a nonce and a threeDSecureInfo.threeDSecureAuthenticationId that confirm the card passed 3D Secure verification.
Braintree returns a validation error if a field doesn't follow Cardinal's documentation.
Integrate 3D Secure from the server side
An alternative to the client-side flow is to make the 3D Secure call from your server instead of from the client device. To meet the device data collection requirements for 3D Secure, you either make a prerequisite prepareLookup call in the client SDK or pass the browser fields directly as input parameters.
Prepare the 3D Secure lookup
The prepareLookup call returns the data needed to perform a 3D Secure lookup call. You trigger this call from the client's device. Pass the payload this call returns to your server so it can perform the lookup call.
- JavaScript
try {
const payload = await threeDSecure.prepareLookup({
nonce: hostedFieldsTokenizationPayload.nonce,
bin: hostedFieldsTokenizationPayload.details.bin
});
// Send payload to server to do server side lookup
} catch (err) {
console.error(err);
return;
}A successful call resolves payload, which you send to your server to perform the lookup. If the call throws, catch receives the error as err.
Make the 3D Secure lookup call
Use the GraphQL mutation performThreeDSecureLookup to attempt 3D Secure authentication on a credit card payment method. This may consume the payment method and return a new single-use payment method.
Including device data is mandatory. Pass along either the dfReferenceId or browserInformation.
- Mutation
mutation PerformThreeDSecureLookup($input: PerformThreeDSecureLookupInput!) {
performThreeDSecureLookup(input: $input) {
clientMutationId
threeDSecureLookupData {
authenticationId
}
paymentMethod {
id
details {
... on CreditCardDetails {
bin
threeDSecure {
authentication {
cavv
eciFlag
liabilityShifted
liabilityShiftPossible
}
}
}
}
}
}
}- Variables
{
input: {
paymentMethodId: single_use_payment_method_id,
amount: "10.00",
transactionInformation: {
browserInformation:
{
javaEnabled: false,
acceptHeader: "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
language: "en-GB",
colorDepth: 24,
screenHeight: 720,
screenWidth: 1280,
timeZone: "0",
userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safar i/537.36",
javascriptEnabled: true,
}
ipAddress: "82.34.105.112",
deviceChannel: "BROWSER",
},
}
}A successful call returns a threeDSecureLookupData.authenticationId and a paymentMethod object whose threeDSecure.authentication block includes the cavv, eciFlag, liabilityShifted, and liabilityShiftPossible values.
Trigger the 3D Secure challenge
This call launches the iframe challenge using a 3D Secure lookup response from a server-side lookup. You only need this call if a challenge is required.
- JavaScript
async function initializeChallenge() {
try {
const payload = await threeDSecure.initializeChallengeWithLookupResponse(lookupResponseFromServer);
if (payload.threeDSecureInfo.liabilityShifted) {
// Liability has shifted
submitNonceToServer(payload.nonce);
} else if (payload.threeDSecureInfo.liabilityShiftPossible) {
// Liability may still be shifted
// Decide if you want to submit the nonce
} else {
// Liability has not shifted and will not shift
// Decide if you want to submit the nonce
}
} catch (err) {
// Handle the challenge error.
}
}Check payload.threeDSecureInfo.liabilityShifted to confirm whether liability shifted to the card issuer before you decide whether to submit the nonce.