3D Secure 2.0 card payments with Braintree
Braintree offers an online card payment service that integrates with .NET web applications (among others). It helps your application to comply with PCI and allows payments to be verified using 3D Secure. Furthermore, in light of PSD2 and Strong Customer Authentication (SCA) requirements, Braintree has adopted 3D Secure 2.0.
In this article, I demonstrate how to integrate a .NET Core web application with Braintree for 3D Secure 2.0 card payments using the Drop-in UI.
Get a sandbox environment
The sandbox allows developers to test Braintree integration in their dev and test environments.
Signing up for a sandbox is free. You can do this on Braintree’s Sandbox page. You will receive an email with instructions for activating your account. Once you’ve completed this step and signed in, you will see the following keys displayed on the home page:
- Merchant ID
- Public Key
- Private Key
Take note of these keys, as they will be used in the sections below.
The client token
Before a payment can be made, the first step is to send a client token from the server to the front-end. The server obtains this token from Braintree.
The token will be used by the front-end when it renders your card payment screen and is included in communications with Braintree.
Install the client library on your server
For the server to talk to Braintree, you need to install the Braintree client library. The client library for .NET is available as a NuGet package, which you can find below:
You can add a reference to your server project in Visual Studio Code using the following terminal command:
dotnet add package Braintree
Generate a client token
A gateway to Braintree is needed to generate tokens. On your server, create an instance of the BraintreeGateway
class from the Braintree
namespace, and set the three keys from your sandbox as well as the Environment
property, e.g.
var gateway = new BraintreeGateway
{
Environment = Braintree.Environment.SANDBOX,
MerchantId = "Merchant ID",
PublicKey = "Public Key",
PrivateKey = "Private Key"
};
(These values will be different for the live system, so in the real world it makes sense to load them from a config file.)
The client token is a simple string and is generated by calling the Generate
method on the ClientToken
property of the gateway object, e.g.
var token = gateway.ClientToken.Generate();
Note that you can keep using the same gateway instance throughout the lifetime of your application. Pass the token to your front-end whenever it needs to render a new card payment page, e.g. by including it in the model to a Razor View.
The card payment screen
When the front-end renders the card payment screen, it uses the client token received from the server to initialize components from the Braintree SDK in JavaScript.
Card details are captured in fields hosted by Braintree, which returns a payment method nonce to the front-end. This nonce is used in a subsequent call for the 3D Secure verification step, which returns a second nonce. The front-end will send this final nonce to the server to close the loop.
Include the JavaScript SDK
The web page that will be used for card payments will need to import three JavaScript files from Braintree. The first is the main SDK:
<script src="https://js.braintreegateway.com/web/3.47.0/js/client.min.js"></script>
Next is the Drop-in UI component:
<script src="https://js.braintreegateway.com/web/dropin/1.18.0/js/dropin.min.js"></script>
Finally, this script is for the 3D Secure component:
<script src="https://js.braintreegateway.com/web/3.47.0/js/three-d-secure.min.js"></script>
Note: 3D Secure 2.0 requires SDK version 3.47 or higher.
Initialize the Drop-in UI
Braintree offers two options for integrating your front-end — Hosted Fields and Drop-in UI. In this article, I will be using the Drop-in UI, but you will find a comparison of the two by following the first link.
The Drop-in UI component injects a div
element with input fields hosted on Braintree’s site (achieved through the magic of the iframe
). This <div>
is identified at initialization using a CSS selector. Put the <div>
where you want the UI to be rendered. By default, it looks something like this:
Initialize the Drop-in UI by calling braintree.dropin.create
. Your JavaScript will resemble the following:
braintree.dropin.create({
authorization: "client_token",
container: "#container_id"
},
function (dropInError, dropInInstance) {
if (dropInError) {
// Handle initialization errors here
return;
}// Use the instance here
}
The first parameter is an object with two properties:
authorization
is the client token from your server.container
is a CSS selector for the target<div>
.
The second parameter is a callback function that Braintree will call once the component has been initialized. If an error occurs, an error object is passed as the first argument; otherwise, the error object is null
and the new component instance is passed as the second argument. (This pattern is standard throughout the Braintree JavaScript SDK.)
As in the example above, the first thing you should do in the body of the callback is to handle errors. After that, you can proceed to make use of the new drop-in instance. In our case, before we touch the instance, we need to initialize the 3D Secure component as well.
Initialize the 3D Secure component
To initialize the 3D Secure component, call braintree.threeDSecure.create
as in the example below:
braintree.threeDSecure.create({
authorization: "client_token",
version: 2
},
function (threeDSecureError, threeDSecureInstance) {
if (threeDSecureError) {
// Handle initialization errors here
return;
}// Use the instance here
});
The first parameter is once again an object, with two parameters:
authorization
is the client token from your server (the same as before).version
is 2 so that Braintree knows to use 3D Secure 2.0.
As before, the second parameter is a callback that takes two arguments — an error object and a new 3D Secure instance. Once you’ve provided for error handling, the next step is to create an event handler to request the payment method nonce from Braintree.
Request the payment method
If you test your page at this point, you’ll see the Drop-in UI appear shortly after the page is loaded. The user can capture their details, and there is built-in validation. What you need next is a way to trigger the transaction.
Add a button to your page and hook up a click event listener that calls the requestPaymentMethod
function on your drop-in component (dropInInstance
in the code above), e.g.
payButton.addEventListener('click', function () {
event.preventDefault();dropInInstance.requestPaymentMethod(function (requestPaymentMethodErr, requestPaymentPayload) {
if (requestPaymentMethodErr) {
// Handle errors here
return;
}// Use requestPaymentPayload.nonce here
});
});
This function takes only one parameter — a callback function. Braintree calls this to return the payment method, passing a potential error object and a payload object. The payload contains the payment method nonce, which you will use for the next step.
Verify the card using 3D Secure
The verifyCard
method of the 3D Secure component (threeDSecureInstance
in the code above) is used to verify the payment method, as in the example below:
threeDSecureInstance.verifyCard({
amount: 15,
nonce: payload.nonce,
bin: payload.details.bin,
email: "customer_email",
billingAddress: { /* address */ },
additionalInformation: { /* more info */ },
onLookupComplete: function (data, next) {
// Use look-up data here
next();
}
},
function (verifyError, verifyResponse) {
if (verifyError) {
// Handle errors here
return;
}// Submit verifyResponse.nonce to your server
});
The first parameter is an object with many notable properties:
amount
is the transaction amount.nonce
is the nonce from the payload returned byrequestPaymentMethod
in the section above.bin
is a Bank Identification Number and can be obtained from the same payload usingdetails.bin
.billingAddress
andadditionalInformation
are optional. You may omit these fields, but Braintree recommends including them in order to reduce the need for authentication challenges. For more detail, see the Braintree 3D Secure 2.0 adoption guide.onLookupComplete
is a callback that allows you to inspect the 3DS look-up data before calling thenext
function.
The second parameter is a callback that receives an error object and a payload that contains the new nonce, which shall be sent to your server to finalize the transaction. The callback is invoked by Braintree once the user has completed the 3D Secure challenge, which appears in an overlay on the card payment page.
Note: To test 3D Secure 2.0 in the sandbox environment, you need to use a very specific set of test values. Values that do not appear in this list will cause Braintree to default to an older version of 3DS.
Warning: Sending through an amount
of zero results in an HTTP 422 error (unprocessable entity) in the Braintree API. I’m noting this down because this sort of thing can happen during development and it might not be obvious what has gone wrong.
After accounting for errors, pass the new nonce to your server, e.g. via an AJAX call, or by including the value in a hidden input field on a <form>
and submitting it to the back-end.
Process the payment on the server-side
Having verified the payment method using 3D Secure, the front-end sends the nonce to the server.
The transaction is only created once the server sends this nonce to Braintree in a call to process the sale.
Verify that 3D Secure was used
Before putting the sale through, you probably want to confirm that the card was verified using 3D Secure. This is done by looking up information about the payment method using the Find
method on the PaymentMethodNonce
property of the Braintree gateway object you created before. Pass in the nonce string received from the front-end, e.g.
var paymentMethodNonce = gateway.PaymentMethodNonce.Find(nonce);if (paymentMethodNonce.ThreeDSecureInfo == null)
{
// 3D Secure was not used
return;
}
This returns a PaymentMethodNonce
object. If its ThreeDSecureInfo
property is null
, the payment method was not verified using 3D Secure. In this case, you may want to reject the transaction, log an error, etc. Otherwise, this object contains useful information about the verification result.
If you are satisfied with the payment method, it’s time to use the nonce to create the transaction.
Create the transaction
A transaction is created by calling the Sale
method on the Transaction
property of the Braintree gateway, passing in a TransactionRequest
instance:
var request = new TransactionRequest
{
Amount = amount,
PaymentMethodNonce = nonce,
Options = new TransactionOptionsRequest
{
SubmitForSettlement = true
}
};var result = _gateway.Transaction.Sale(request);
The Amount
property is a decimal that represents the amount that will be charged. The PaymentMethodNonce
is the nonce string that was received from the front-end and used in the 3D Secure verification step above. The Sale
method returns a Result<Transaction>
instance, which you can inspect to see whether or not the transaction was successful, e.g.
if (!result.IsSuccess())
{
// Handle transaction errors
// Check result.Transaction.Status
}
If the IsSuccess
method returns false, you can look at the Status
property of the Transaction
for more detail.
View transactions
Transactions created in the sandbox can be viewed on the Braintree website.
Sign in to your sandbox account and do a transaction search. If you have successfully created transactions during testing, they will appear in this report.
Used for this article
- Visual Studio Code 1.36.1
- .NET Core 2.2.300
- Braintree .NET 4.12.0