note

We have upgraded our 3D Secure integration in preparation for 3DS 2 and PSD2 Strong Consumer Authentication (SCA) compliance requirements in 2019.

This guide shows our integration for 3DS 2.

Generate a client token

important

You must generate a client token if you want to use 3D Secure (3DS). Tokenization keys can't be used to verify 3D Secure enabled cards.

Before you can call ThreeDSecure#performVerification, you will need to set up the SDK and initialize a BraintreeFragment with a client token generated on your server.

Additionally, add the following Maven repository and (non-sensitive) credentials to your app-level gradle:

Groovy
repositories {
    maven {
        url "https://cardinalcommerce.bintray.com/android"
        credentials {
            username 'braintree-team-sdk@cardinalcommerce'
            password '220cc9476025679c4e5c843666c27d97cfb0f951'
        }
    }
}

If you're using the Google Play Services Gradle plugin, you will also need to add this to your build.gradle to avoid a dependency resolution issue:

Groovy
dependencies {
    // Your dependency declarations...
    components.all {
        allVariants {
            withDependencies { deps ->
                deps.each { dep ->
                    if (dep.group == 'net.minidev' && dep.name =='json-smart') {
                            dep.version {
                                prefer "2.3"
                            }
                            dep.because "resolving dependencies issue"
                    }
                }
            }
        }
    }
}

Specify a merchant account

If you would like to use a merchant account ID other than your default, specify the merchant_account_id when generating the client token.

note

The merchant account ID used to create the client token must match the merchant account ID used to create the subsequent transaction.

Using 3DS

Drop-in UI

important

3DS 2 support requires Drop-in version 4.3.0 or higher.

First, make sure to include our Drop-in in your project. Then, declare a URL scheme in your AndroidManifest.

To use 3DS 2, 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. This object must contain the following fields:

  • amount
  • versionRequested (You should pass ThreeDSecureRequest.VERSION_2 here)

And should contain as many of the following fields as possible:

ThreeDSecurePostalAddress address = new ThreeDSecurePostalAddress()
    .givenName("Jill") // ASCII-printable characters required, else will throw a validation error
    .surname("Doe") // ASCII-printable characters required, else will throw a validation error
    .phoneNumber("5551234567")
    .streetAddress("555 Smith St")
    .extendedAddress("#2")
    .locality("Chicago")
    .region("IL")
    .postalCode("12345")
    .countryCodeAlpha2("US");

// For best results, provide as many additional elements as possible.
ThreeDSecureAdditionalInformation additionalInformation = new ThreeDSecureAdditionalInformation()
    .shippingAddress(address);

ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest()
    .amount("10.00")
    .email("test@email.com")
    .billingAddress(address);
    .versionRequested(ThreeDSecureRequest.VERSION_2)
    .additionalInformation(additionalInformation);

Then, add the ThreeDSecureRequest to your DropInRequest, set requestThreeDSecureVerification on your DropInRequest to true, and start the Drop-in.

DropInRequest dropInRequest = new DropInRequest()
    .requestThreeDSecureVerification(true)
    .threeDSecureRequest(threeDSecureRequest);

startActivityForResult(dropInRequest.getIntent(this), REQUEST_CODE_CONST);

Custom UI

important

3DS 2 support requires Braintree version 3.4.2 or higher.

To enable 3DS, declare a URL scheme in your AndroidManifest.

Add the following to your app-level build.gradle file:

Groovy
dependencies {
    implementation 'com.braintreepayments.api:braintree:3.6.0'
    implementation 'com.braintreepayments.api:three-d-secure:3.4.2'
}

To use 3DS, you will need to create a ThreeDSecureRequest with relevant customer and transaction data in order to minimize the need for issuing banks to present authentication challenges to customers. This object must contain the following fields:

  • amount
  • nonce
  • versionRequested (You should pass ThreeDSecureRequest.VERSION_2 here)

And should contain as many of the following fields as possible:

// Card nonce that we wish to upgrade to a 3DS nonce.
CardNonce cardNonce = (CardNonce) paymentMethodNonce;

ThreeDSecurePostalAddress address = new ThreeDSecurePostalAddress()
    .givenName("Jill") // ASCII-printable characters required, else will throw a validation error
    .surname("Doe") // ASCII-printable characters required, else will throw a validation error
    .phoneNumber("5551234567")
    .streetAddress("555 Smith St")
    .extendedAddress("#2")
    .locality("Chicago")
    .region("IL")
    .postalCode("12345")
    .countryCodeAlpha2("US");

// For best results, provide as many additional elements as possible.
ThreeDSecureAdditionalInformation additionalInformation = new ThreeDSecureAdditionalInformation()
    .shippingAddress(address);

ThreeDSecureRequest threeDSecureRequest = new ThreeDSecureRequest()
    .amount("10")
    .email("test@email.com")
    .billingAddress(address);
    .nonce(cardNonce.getNonce())
    .versionRequested(ThreeDSecureRequest.VERSION_2)
    .additionalInformation(additionalInformation);

Once you initialize an instance of BraintreeFragment, you can verify transactions with ThreeDSecure#performVerification. This call will refer to the card data based on the payment method nonce and challenge the cardholder with a 3D Secure authentication, if the card is enrolled in a 3D Secure program (e.g. Verified by Visa).

When you call ThreeDSecure#performVerification, pass in the newly-created ThreeDSecureRequest. You will also need to override the required method onLookupComplete, which will be invoked after receiving the ThreeDSecure lookup response, before initializing the challenge and completing the flow.

ThreeDSecure.performVerification(mBraintreeFragment, threeDSecureRequest, new ThreeDSecureLookupListener() {
    @Override
    public void onLookupComplete(ThreeDSecureRequest request, ThreeDSecureLookup lookup) {
        // Optionally inspect the lookup result and prepare UI if a challenge is required
        ThreeDSecure.continuePerformVerification(mBraintreeFragment, request, lookup);
    }
});

Once the user completes the 3D Secure process, BraintreeFragment will notify the BraintreeListeners with the result. Be prepared to handle the errors in your BraintreeErrorListener or the PaymentMethodNonce in PaymentMethodCreatedListener. When your PaymentMethodCreatedListener receives a PaymentMethodNonce, transmit PaymentMethodNonce#getNonce() to your server and create a transaction.

Java
@Override
public void onError(Exception error) {
  // Handle the error
}

@Override
public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) {
  String paymentMethodNonce = paymentMethodNonce.getNonce();
  // Upload paymentMethodNonce to your server.
}

Verify a vaulted credit card

First, on the server, generate and return a payment method nonce for the vaulted credit card.

Then on the client, you can use the ThreeDSecure#performVerification method just as before and pass it the newly-generated nonce.

Validation errors

Braintree will evaluate any fields passed against Cardinal's documentation. You will receive a validation error from Braintree if a field is incorrect.

Advanced client-side options

We expose additional information about the authentication request that you can use for more advanced UI flows or risk assessment. You should be aware that making such assessments may result in accepting the liability for fraudulent transactions.

These parameters pass through the client-side first and should not be trusted for your server-side risk assessment. They should be used for UI flow only.

Java
@Override
public void onPaymentMethodCreated(PaymentMethod paymentMethod) {
  Card card = (Card) paymentMethod;

  boolean liabilityShifted = card.getThreeDSecureInfo().isLiabilityShifted(); // true || false
  boolean liabilityShiftPossible = card.getThreeDSecureInfo().isLiabilityShiftPossible(); // true || false
}
  1. liabilityShifted indicates that 3D Secure worked and authentication succeeded. This will also be true if the issuing bank does not support 3D Secure, but the payment method does. In both cases, the liability for fraud has been shifted to the bank. You should go on creating a transaction using the new nonce.
  2. liabilityShiftPossible indicates that the payment method was eligible for 3D Secure. If liabilityShifted is false, then the user failed 3D Secure authentication. In this situation, the card brands recommend asking the user for another form of payment. However, if you have server-side risk assessment processes that allow for it, you can still use the new nonce to create a transaction. If you want to use a nonce that did not pass 3D Secure authentication, you need to set the required option to false in your server integration.
  3. If both of the above values are false then this card was ineligible for 3D Secure. You can continue to create the transaction with the new nonce. However, liability shift will not apply to this transaction. This case may be useful if you would like to ask the user for additional verification (AVS, etc).
important

For American Express SafeKey, liabilityShifted may be returned as true but Amex may later revoke the liability shift for the transaction based on your merchant behavior and fraud rate.

Verify a card from raw details or a payment method

To perform a verification on raw card details, we provide a convenience method:

Java
CardBuilder cardBuilder = new CardBuilder()
  .cardNumber("4111111111111111")
  .expirationDate("12/2020");

ThreeDSecure.performVerification(mBraintreeFragment, cardBuilder, amount);

Next Page: Server-side →