3D Secure

Client-Side Implementationanchor

Generate a client tokenanchor

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 initialize BTPaymentFlowDriver, you will need to set up the SDK and initialize it with a client token generated on your server.

Specify a merchant accountanchor

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 or verification.

Using 3DSanchor

To enable 3DS, set up a URL Scheme in your project. This allows your app to open a SFSafariViewController to complete the 3D Secure verification workflow and return.

Drop-in UIanchor

important

3DS2 support requires Drop-in version 7.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 vaultCard 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.

If you haven't already, include the Drop-in in your project.

You will need to create a BTThreeDSecureRequest 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 .version2 here)

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

  1. Swift
let threeDSecureRequest = BTThreeDSecureRequest()
threeDSecureRequest.amount = 10.00
threeDSecureRequest.email = "test@email.com"

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

// Optional additional information.
// For best results, provide as many of these elements as possible.
let info = BTThreeDSecureAdditionalInformation()
info.shippingAddress = address
threeDSecureRequest.additionalInformation = info

let dropInRequest = BTDropInRequest()
dropInRequest.threeDSecureRequest = threeDSecureRequest

let dropIn = BTDropInController(authorization: self.authorizationString, request: dropInRequest) { (controller, result, error) in
    if (error != nil) {
        // Handle error
    } else {
        // Use the nonce returned in 'result.paymentMethod'
    }
    controller.dismiss(animated: true, completion: nil)
}

Custom UIanchor

The following instructions assume your app has already integrated Credit Card payments.

CocoaPodsanchor

Include Braintree/ThreeDSecure in your podfile:

  1. Ruby
pod 'Braintree/ThreeDSecure'

Carthageanchor

Add github "braintree/braintree_ios" to your Cartfile, and add the frameworks to your project.

You must include all of the following frameworks via Carthage:

  • CardinalMobile.framework
  • BraintreeCore.framework
  • BraintreeCard.framework
  • BraintreePaymentFlow.framework
  • BraintreeThreeDSecure.framework
  • PayPalDataCollector.framework

Swift Package Manageranchor

You must include the BraintreeThreeDSecure and PayPalDataCollector frameworks.

Implementationanchor

First, initialize the BTPaymentFlowDriver and set the viewControllerPresentingDelegate:

  1. Swift
class MyCheckoutViewController: UIViewController, BTViewControllerPresentingDelegate {

    var paymentFlowDriver: BTPaymentFlowDriver!

    func setupPaymentFlowDriver() {
        self.paymentFlowDriver = BTPaymentFlowDriver(apiClient: self.apiClient)
        self.paymentFlowDriver.viewControllerPresentingDelegate = self
    }
}

Next, conform your view controller to BTViewControllerPresentingDelegate in order to handle view controller presentation.

  1. Swift
func paymentDriver(_ driver: Any, requestsPresentationOf viewController: UIViewController) {
    present(viewController, animated: true, completion: nil)
}

func paymentDriver(_ driver: Any, requestsDismissalOf viewController: UIViewController) {
    dismiss(animated: true, completion: nil)
}

Once configuration is complete, you will need to create a BTThreeDSecureRequest 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 BTThreeDSecureVersion2 here)

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

  1. Swift
let threeDSecureRequest = BTThreeDSecureRequest()
threeDSecureRequest.amount = 10.00
threeDSecureRequest.nonce = tokenizedCard.nonce
threeDSecureRequest.email = "test@email.com"
threeDSecureRequest.versionRequested = .version2

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

// Optional additional information.
// For best results, provide as many of these elements as possible.
let info = BTThreeDSecureAdditionalInformation()
info.shippingAddress = address
threeDSecureRequest.additionalInformation = info

Then, call startPaymentFlow, passing in the ThreeDSecureRequest.

  1. Swift
func tappedCheckout() {
    // Example: Create a BTCard based on the UI state
    let details = BTCard()
    details.number = cardNumberField.text
    details.expirationMonth = expirationMonthField.text
    details.expirationYear = expirationYearField.text

    // Tokenize the card
    cardClient.tokenizeCard(details) { (tokenizedCard, error) in
        guard let tokenizedCard = tokenizedCard else {
            // Handle error
            return
        }

        // Make sure that self conforms to the BTThreeDSecureRequestDelegate protocol
        threeDSecureRequest.threeDSecureRequestDelegate = self

        self.paymentFlowDriver.startPaymentFlow(request) { (result, error) in
            guard let result = result as? BTThreeDSecureResult, let tokenizedCard = result.tokenizedCard else {
                // Handle error
                return
            }

            if (tokenizedCard.threeDSecureInfo.liabilityShiftPossible) {
                if (tokenizedCard.threeDSecureInfo.liabilityShifted) {
                    // 3D Secure authentication success
                } else {
                    // 3D Secure authentication failed
                }
            } else {
                // 3D Secure authentication was not possible
            }

            // Use the 'tokenizedCard.nonce'
        }
    }
}

You are required to implement the onLookupComplete method where you can optionally inspect the lookup result. When ready to continue with the 3DS flow, you must call next().

  1. Swift
func onLookupComplete(_ request: BTThreeDSecureRequest, result: BTThreeDSecureResult, next: @escaping () -> Void) {
    // Optionally inspect 'result.lookup' and prepare UI if a challenge is required
    next()
}
  • If the user successfully completes the 3D Secure process, the startPaymentFlow callback block will receive a BTThreeDSecureResult with a tokenizedCard property. You should transmit the tokenizedCard.nonce to your server and create a transaction.

  • If the user cancels the 3D Secure authentication, the completion block will be called with an error where code is BTPaymentFlowDriverErrorTypeCanceled.

  • If the 3D Secure process fails, the completion block will be called with an error.

In order to perform 3D Secure authentication again, a new nonce needs to be supplied.

For each request to verify a card, the completion block will be called exactly once.

Verify a vaulted credit cardanchor

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

Then on the client, you can use the startPaymentFlow:completion: method just as before and pass it the newly-generated nonce.

Validation errorsanchor

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 optionsanchor

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.

  1. Swift
// In this example, 'card' is a 'BTCardNonce'.
if (card.threeDSecureInfo.liabilityShiftPossible) {
    if (card.threeDSecureInfo.liabilityShifted) {
        // 3D Secure authentication success
    } else {
        // 3D Secure authentication failed
    }
} else {
    // 3D Secure authentication was not possible
}
  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.

Using 3D Secure with a CVV-only nonceanchor

If you want to use a CVV-only nonce when creating a transaction with 3D Secure, you will need to pass a 3D Secure Authentication ID together with a CVV-only nonce when creating a transaction, creating a payment method, or creating a customer with a payment method

Using 3D Secure Data-Onlyanchor

To use use the 3D Secure data-only protocol for a given cardbrand, add the dataOnlyRequested boolean, and check for the resulting status in the onLookupComplete() callback:

  1. Swift
let threeDSecureRequest = BTThreeDSecureRequest()
threeDSecureRequest.amount = 10.00
threeDSecureRequest.nonce = tokenizedCard.nonce
threeDSecureRequest.email = "test@email.com"
threeDSecureRequest.dataOnlyRequested = true

Using accountType for combo cards in Brazilanchor

When processing Brazilian cards domestically, customers with combo cards should be given the opportunity to select the account type of their card. To do this, generate a UI for this selection and reflect that choice in the 3D Secure call, as well as the corresponding transaction, payment method or customer API call.

  1. Swift
let threeDSecureRequest = BTThreeDSecureRequest()
threeDSecureRequest.amount = 10.00
threeDSecureRequest.nonce = tokenizedCard.nonce
threeDSecureRequest.email = "test@email.com"
threeDSecureRequest.accountType = .credit

See also


Next Page: Server-side