3D Secure
Step by Step Integration
Table of Contents
3DS Client side flow
Generate a client token
The SSL certificates for Braintree Mobile (iOS and Android) SDKs are set to expire on March 30, 2026. This will impact existing versions of the SDK in published versions
of your app. To reduce the impact, upgrade the
If you do not decommission your app versions that include the older SDK versions or force upgrade your app with the updated certificates by the expiration date, 100% of your customer traffic will fail.
Before you can initialize a ThreeDSecureClient
, you will need
to set up the SDK and
initialize a
BraintreeClient
with a
ClientTokenProvider
.
Additionally, add the following Maven repository and (non-sensitive) credentials to your app-level gradle.
- Groovy
repositories {
maven {
url "https://cardinalcommerceprod.jfrog.io/artifactory/android"
credentials {
username = 'braintree_team_sdk'
password = 'cmVmdGtuOjAxOjIwMzgzMzI5Nzg6Q3U0eUx5Zzl5TDFnZXpQMXpESndSN2tBWHhJ'
}
}
}
If you would like to use a merchant account ID other than your default,
specify the
merchant_account_id
when generating 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
verification.
Verify a card using 3DS
Create a request
To use 3DS, you will need to create a
ThreeDSecureRequest
object with relevant customer and
transaction data in order to minimize the need for issuing banks to present
authentication challenges to customers.
The ThreeDSecureRequest object must contain the following fields:
amount
nonce
The object should contain as many of the following fields as possible. The full list of fields is described in the SDK documentation.
- Java
- Kotlin
ThreeDSecurePostalAddress address = new ThreeDSecurePostalAddress();
address.setGivenName("Jill"); // ASCII-printable characters required, else will throw a validation error
address.setSurname("Doe"); // ASCII-printable characters required, else will throw a validation error
address.setPhoneNumber("5551234567");
address.setStreetAddress("555 Smith St");
address.setExtendedAddress("#2");
address.setLocality("Chicago");
address.setRegion("IL"); // ISO-3166-2 code
address.setPostalCode("12345");
address.setCountryCodeAlpha2("US");
// For best results, provide as many additional elements as possible.
ThreeDSecureAdditionalInformation additionalInformation = new ThreeDSecureAdditionalInformation();
additionalInformation.setShippingAddress(address);
ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest();
threeDSecureRequest.setAmount("10.00");
threeDSecureRequest.setEmail("test@email.com");
threeDSecureRequest.setBillingAddress(address);
threeDSecureRequest.setVersionRequested(ThreeDSecureRequest.VERSION_2);
threeDSecureRequest.setAdditionalInformation(additionalInformation);
Drop-in UI
3DS support requires Drop-in version 4.3.0 or higher.
If you are using the Drop-In UI to tokenize cards, you have
CVV rules enabled
and you run 3D Secure verifications, the default setting to vault cards on
your client will result in a processor error. Instead, you should disable
vaulting via the Drop-In UI and vault the card on your server. You can do
so by setting
vaultCardDefaultValue
to false
when initializing the Drop-In UI and include the
vault_on_success=true
parameter when creating a transaction
using transaction:sale or a GraphQL mutation from your server.
First, make sure to include our Drop-in in your project. Next, declare a URL scheme in your AndroidManifest. This allows your app to switch to a browser to complete the 3D Secure verification workflow and return.
The ThreeDSecureRequest object must contain the following fields:
amount
versionRequested
(set asThreeDSecureRequest.VERSION_2
)
- Java
- Kotlin
ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest();
threeDSecureRequest.setAmount("10.00");
threeDSecureRequest.setVersionRequested(ThreeDSecureRequest.VERSION_2);
//Pass other 3DS parameters here
Then, add the ThreeDSecureRequest
object to your
DropInRequest
.
- Java
- Kotlin
DropInRequest dropInRequest = new DropInRequest();
dropInRequest.setThreeDSecureRequest(threeDSecureRequest);
Custom UI
To make sure your app can complete a 3D Secure verification, declare a URL scheme in your AndroidManifest. This will allow Android to return to your app from a browser-based verification flow.
Add the following to your app-level build.gradle
file:
- Kotlin
- Groovy
dependencies {
implementation("com.braintreepayments.api:three-d-secure:4.49.1")
}
The ThreeDSecureRequest object must contain the following fields:
amount
nonce
versionRequested
(set asThreeDSecureRequest.VERSION_2
)
- Java
- Kotlin
// Card nonce that we wish to upgrade to a 3DS nonce.
CardNonce cardNonce = (CardNonce) paymentMethodNonce;
ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest();
threeDSecureRequest.setAmount("10.00");
threeDSecureRequest.setNonce(cardNonce.getString());
threeDSecureRequest.setVersionRequested(ThreeDSecureRequest.VERSION_2);
//Pass other 3DS parameters here
To
verify vaulted cards, you would need to first generate the nonce on the server and then pass
it in the ThreeDSecureRequest
.
You can submit a ThreeDSecureRequest
object by calling
ThreeDSecureClient#performVerification
. If a card is enrolled
in a 3D Secure program (e.g. Verified by Visa), the sdk will present a 3D
Secure authentication challenge using card data linked to a payment method
nonce.
- Java
- Kotlin
BraintreeClient braintreeClient = new BraintreeClient(this, new ExampleClientTokenProvider());
ThreeDSecureClient threeDSecureClient = new ThreeDSecureClient(this, braintreeClient);
threeDSecureClient.performVerification(activity, threeDSecureRequest, (threeDSecureLookupResult, lookupError) -> {
// optional: inspect the lookup result and prepare UI if a challenge is required
threeDSecureClient.continuePerformVerification(activity, threeDSecureRequest, threeDSecureLookupResult);
});
Implement a ThreeDSecureListener
to receive results from the 3D
Secure flow. Once the user completes the 3D Secure process, send the nonce
to your server and create a transaction.
- Java
- Kotlin
public class MyActivity extends AppCompatActivity implements ThreeDSecureListener {
@Override
public void onThreeDSecureSuccess(@NonNull ThreeDSecureResult threeDSecureResult) {
// send this nonce to your server
String nonce = threeDSecureResult.getTokenizedCard().getString();
}
@Override
public void onThreeDSecureFailure(@NonNull Exception error) {
if (error instanceof UserCanceledException) {
// user canceled
} else {
// handle error
}
}
}
If you are using using an Activity and your Activity's launch mode is
singleTop
, singleTask
, or
singleInstance
you will also need to override
onNewIntent
:
- Java
- Kotlin
public class MyActivity extends AppCompatActivity {
@Override
protected void onNewIntent(Intent newIntent) {
super.onNewIntent(newIntent);
setIntent(newIntent);
}
}
A validation error from Braintree will be returned if a field does not follow Cardinal's documentation.
3DS Server side flow
An alternative way of performing 3DS is to make the 3DS call from the server instead of from the client machine.
To meet the device data collection requirements for 3DS, merchants must
either make a prerequisite prepareLookup
call in the client SDK
or pass in the browser fields directly as input parameters.
Prepare the 3DS lookup
The prepareLookup
call will return the data needed to perform a
3D Secure lookup call. This call is triggered from the client's device. The
payload returned by this call should be passed on to the server so a 3DS
lookup can be done from there.
- Java
ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest()
.amount("10")
.email("test@email.com")
.billingAddress(address)
.additionalInformation(additionalInfo)
.nonce(paymentMethodNonce)
.versionRequested(ThreeDSecureRequest.VERSION_2);
.accountType(ThreeDSecureRequest.CREDIT);
BraintreeClient braintreeClient = new BraintreeClient(this, new ExampleClientTokenProvider());
ThreeDSecureClient threeDSecureClient = new ThreeDSecureClient(this, braintreeClient);
threeDSecureClient.prepareLookup(context, threeDSecureRequest,
(threeDSecureLookupResult, lookupError) -> {
// Send payload to the server to do server side lookup
}
)
Make the 3DS lookup call
Use the GraphQL mutation performThreeDSecureLookup
to attempt
to perform 3D Secure Authentication on credit card payment method. This may
consume the payment method and return a new single-use payment method.
Including device data is mandatory. This can be done either by passing along
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",
},
}
}
Trigger 3DS challenge
This call will launch the iframe challenge using a 3D Secure lookup response from a server side lookup. This call is only necessary if a challenge is required.
- Java
ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest()
.amount("10")
.email("test@email.com")
.billingAddress(address)
BraintreeClient braintreeClient = new BraintreeClient(this, new ExampleClientTokenProvider());
ThreeDSecureClient threeDSecureClient = new ThreeDSecureClient(this, braintreeClient);
threeDSecureClient.initializeChallengeWithLookupResponse(
activity, request, lookupResponse, new ThreeDSecureResultCallback() {
@Override
public void onResult(@Nullable ThreeDSecureResult threeDSecureResult,
@Nullable Exception error) {
if (threeDSecureResult != null) {
listener.onThreeDSecureSuccess(threeDSecureResult);
} else if (error != null) {
listener.onThreeDSecureFailure(error);
}
}
});
See also
Next Page: Applying 3DS to Transactions and Verifications →