Implementing a 3DS Integration using the 3DS JavaScript API

This guide walks you through the steps required to implement 3-Domain Secure™ (3-D Secure or 3DS) authentication which is designed to protect online purchases against credit card fraud by allowing you to authenticate the payer before submitting an Authorization or Pay transaction.

Note: This guide assumes you are using the Hosted Session card capture method. Please see the Hosted Session integration guide.

Prerequisites

To use Tyro eCommerce 3DS authentication service please see below:

  • You must be registered with Tyro to use 3DS1 and/or 3DS2

  • Your merchant profile on the gateway must be enabled for 3DS

  • You must be integrated to API version 55 or later.

Implementing 3D-Secure

Step 1: Create and Update Session

As a first step, you must create a session, which you can then update with the request fields and values you wish to store in the session.

This is a server-side API call (Create Session) and is a prerequisite for integrating with the JS API.

Note: Before proceeding further, the session will need to be updated with Card details, if the the provided session is a ‘Hosted Session’ this is not needed as the payer’s card details are updated to session upon creation.

However, if you are using the (Create Session) API operation you will need to send an (Update Session) request to provided the necessary payment details - see below example:

URL: https://test-tyro.mtf.gateway.mastercard.com/api/rest/version/58/merchant/{merchantId}/session/{sessionId}

HTTP Method: PUT

Create / Update Session Request
{
  "session": {
    "id": "<session-id>"
  },
  "order": {
    "amount": "1.00",
    "currency": "AUD",
    "id": "<order.id>"
  },
  "transaction": {
    "id": "<transaction.id>"
  },
  "authenication": {
    "channel": "PAYER_BROWSER",
    "purpose": "PAYMENT_TRANSACTION",
    "redirectResponseUrl": "https://tyro.com"
  }
}
Create / Update Session Response
{
  "order": {
    "id": "e8abcf37-166b-411a-9804-0951808acb68",
    "amount": "1.00",
    "currency": "AUD"
  },
  "transaction": {
    "id": "0cae0bd6-e4a8-4605-8913-cc3b0727a722"
  },
  "authentication": {
    "channel": "PAYER_BROWSER",
    "purpose": "PAYMENT_TRANSACTION",
    "redirectResponseUrl": "URL_TO_PVT_TEST_SITE"
  }
}

You must submit the Initiate Authentication operation at the earliest opportunity in your checkout process, and act on the response immediately.

This will typically be when the payer finishes entering their card number on the checkout page

Step 2: Initialize the API

Reference the 3DS JS API (threeDS.js) from the gateway servers. This will place a ThreeDS object into the window/global namespace.

Once you have created a session, initialize the API using the configure( ) method. This method should be called during the page load or when the DOM is in ready state. It should be called only once for the page load. After calling this method, 3DS JS will provide configuration values as member variables.

3DS JS Initialization Request

You can initialize the 3DS JS API by invoking the configure() method, with the following mandatory fields as arguments in a map object:

  • merchantId: Your merchant identifier on the gateway.

  • sessionId: The session Id that you created using the Create Session call.

  • containerId: The <div> id in your html where the API will inject a hidden iframe.

  • callback: A function that will be invoked once the API has been initialized.

  • configuration: JSON value supporting data elements like userLanguage(Optional), REST API version (wsVersion).

Create a blank div element.

You must now create a blank <div> element. The <div> id in your html is where the API will inject a hidden iframe. Please use the following script:

 <body>
        <div id="3DSUI"></div>
    </body>

<script>
 //The output of this call will return 'false', since the API is not configured yet
        console.log(ThreeDS.isConfigured());
        /**
        Configure method with the configuration{} parameter set and demonstrates the state change of the ThreeDS object before and after the configure method is invoked.
        */
        ThreeDS.configure({
            merchantId: {merchantId},
            sessionId: {sessionId},
            containerId: "3DSUI",
            callback: function () {
                if (ThreeDS.isConfigured())
                    console.log("Done with configure");
            },
            configuration: {
                userLanguage: "en-AU", //Optional parameter
                wsVersion: 57
            }
        });
				</script>
				</html>
</body>

Step 3: Initiate Authentication

Once all payer and payment data has been gathered into a session, you can initiate the authentication by invoking the initiateAuthentication() method. It determines the versions of payer authentication available to you for a given card, which will be based on the following:

  • the 3DS versions configured on your merchant profile, for example, 3DS1 or 3DS2

  • the card type

  • preferences you have indicated in the request

  • the version of 3DS the card has been enrolled in

  • the 3DS transaction filtering rules configured by you or your payment service provider.

The operation also enables any background activities (such as a 3DS2 ACS Call) to be carried out for purposes such as gathering additional payer data to support a subsequent authenticatePayer() method.

To allow any ACS call process to complete before you attempt the authenticatePayer() method, it is recommended that you invoke the initiateAuthentication() method at the earliest opportunity in your checkout process, and act on the response immediately.

This will typically be when the payer completes entering their card number on the checkout page (or selecting a card from those recorded against their account, if your site has card-on-file capabilities).

Initiate Authentication Request

You can initiate authentication by providing the following mandatory fields in the initiateAuthentication() method:

  • transactionId: The unique identifier for this payment authentication.

  • orderId: The unique identifier for this order.

  • callback: The callback function.

    • optionalParams: (Optional) argument with any additional Initiate Authentication REST API request fields such as correlationId.
Initiate Authentication Request
var optionalParams = {
    sourceOfFunds: {
        type: "CARD"
    },
    order: {
        walletProvider: "MASTERPASS_ONLINE"
    }
};

ThreeDS.initiateAuthentication({orderId}, {transactionId}, function (data) {
    if (data && data.error) {
        var error = data.error;

        //Something bad happened, the error value will match what is returned by the Authentication API
        console.error("error.code : ", error.code);
        console.error("error.msg : ", error.msg);
        console.error("error.result : ", error.result);
        console.error("error.status : ", error.status);
    } else {
        console.log("After Initiate 3DS ", data);

        //data.response will contain information like gatewayRecommendation, authentication version, etc.
        console.log("REST API raw response ", data.restApiResponse);
        console.log("Correlation Id", data.correlationId);
        console.log("Gateway Recommendation", data.gatewayRecommendation);
        console.log("HTML Redirect Code", data.htmlRedirectCode);
        console.log("Authentication Version", data.authenticationVersion);

        switch (data.gatewayRecommendation) {
            case "PROCEED":
                authenticatePayer();//merchant's method
                break;
            case "DO_NOT_PROCEED":
                displayReceipt(data);//merchant's method, you can offer the payer the option to try another payment method.
                break;
        }
    }
}, optionalParams);

Initiate Authentication Response

If 3DS authentication of the payer is available, the following fields are returned in the data argument of the callback function. Otherwise, the response will include an error.

  • data.restApiResponse: Contains raw response from the Initiate Authentication REST API call.

  • data.correlationId: The last correlation Id that was used for making the Initiate Authentication REST API call. It allows you to match the response to the request.

  • data.gatewayRecommendation

  • data.authenticationVersion: Returns 3DS1 or 3DS2 if authentication is available.

Initiate Authentication Response
{
  "authentication": {
    "3ds2": {
      "methodCompleted": false,
      "methodSupported": "SUPPORTED"
    },
    "redirect": {
      "customized": {
        "3DS": {
          "methodPostData": "eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9xYTA0LmdhdGV3YXkubWFzdGVyY2FyZC5jb20vY2FsbGJhY2tJbnRlcmZhY2UvZ2F0ZXdheS80ZjNmMGQyMjM5NzQwODE2OWIwMWFiYzg2OTQyZTY5NzBmODA2M2M0MDU4ZjAzNjNlOTFlMmJiOTNkOTA0NzU3IiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhYWY5YjU5ZC0yZTA0LTRjZDUtOTQzOC01OGU4MGEzNzBiNWEifQ==",
          "methodUrl": "<method_url>"
        }
      }
    },
    "redirectHtml": "<div id=\"initiate3dsSimpleRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <iframe id=\"methodFrame\" name=\"methodFrame\" height=\"100\" width=\"200\" > </iframe> <form id =\"initiate3dsSimpleRedirectForm\" method=\"POST\" action=\"https://<host_name>/acs/v2/method\" target=\"methodFrame\"> <input type=\"hidden\" name=\"threeDSMethodData\" value=\"eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9xYTA0LmdhdGV3YXkubWFzdGVyY2FyZC5jb20vY2FsbGJhY2tJbnRlcmZhY2UvZ2F0ZXdheS80ZjNmMGQyMjM5NzQwODE2OWIwMWFiYzg2OTQyZTY5NzBmODA2M2M0MDU4ZjAzNjNlOTFlMmJiOTNkOTA0NzU3IiwidGhyZWVEU1NlcnZlclRyYW5zSUQiOiJhYWY5YjU5ZC0yZTA0LTRjZDUtOTQzOC01OGU4MGEzNzBiNWEifQ==\" /> </form> <script>document.getElementById(\"initiate3dsSimpleRedirectForm\").submit();</script> </div>",
    "version": "3DS2"
  },
  "order": {
    "currency": "AUD",
    "status": "AUTHENTICATION_INITIATED"
  },
  "response": {
    "gatewayCode": "AUTHENTICATION_IN_PROGRESS",
    "gatewayRecommendation": "PROCEED_WITH_AUTHENTICATION"
  },
  "result": "SUCCESS",
  "sourceOfFunds": {
    "provided": {
      "card": {
        "number": "512345xxxxxx0008"
      }
    },
    "type": "CARD"
  },
  "transaction": {
    "authenticationStatus": "AUTHENTICATION_AVAILABLE"
  },
  "version": "58"
}

To determine the next step, check the gateway’s recommendation provided in the gatewayRecommendation field. Please note that this recommendation is only based on the 3DS transaction filtering rules configured by you or your payment service provider.

gatewayRecommendation: DO_NOT_PROCEED

Do not proceed with 3DS authentication for this card. You can offer the payer the option to try another payment method.

gatewayRecommendation: PROCEED

You can proceed to authenticate the payer using the authenticatePayer( ) method call.

Step 4: Authenticate Payer

Where the Initiate Authentication response has indicated authentication to be available (authenticationVersion=3DS1 or 3DS2), you can invoke the authenticatePayer() function. You should invoke this when the payer clicks the “Pay Now” button on the checkout page.

Authenticate Payer Request

You must invoke the authenticatePayer() method by providing the following mandatory fields:

  • orderId: The same orderId as the initiateAuthentication() method that preceded it.
  • transactionId: The same transactionId as the initiateAuthentication() method that preceded it.
  • callback: The callback function.
  • optionalParams: (Optional) argument with any additional Authenticate Payer REST API request fields such as billing and shipping.
Authenticate Payer Request
var optionalParams = {
    fullScreenRedirect: true,
    billing: {
        address: {
            city: "Sydney",
            country: "AUS"
        }
    }
};
 
ThreeDS.authenticatePayer({orderId}, {transactionId}, function (data) {
    if (!data.error) {
        //data.response will contain all the response payload from the AUTHENTICATE_PAYER call.
        console.log("REST API response ", data.restApiResponse);
        console.log("HTML redirect code", data.htmlRedirectCode);
        displayReceipt(data);
    }
}, optionalParams);
 
 
function displayReceipt(apiResponse) {
    var responseBody = {
        "apiResponse": apiResponse
    };
 
    var xhr = new XMLHttpRequest();
    xhr.open('PUT', '3dsreceipt', true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.onreadystatechange = function () {
        if (xhr.readyState == XMLHttpRequest.DONE) {
            document.documentElement.innerHTML = this.response;
        }
    }
    xhr.send(JSON.stringify(responseBody));
}
	

Authenticate Payer Response

The following fields are returned in the data argument of the callback function:

  • data.restApiResponse: Contains raw response from the Authentication Payer REST API call.
  • data.correlationId: The last correlation Id that was used for making the Authentication Payer REST API call. It allows you to match the response to the request.
  • data.gatewayRecommendation
  • data.htmlRedirectCode: The gateway always returns this field for insertion into the page displayed to the payer.

To determine the next step, check the gateway’s recommendation provided in the gatewayRecommendation field returned in the callback. Please note that this recommendation is only based on the 3DS transaction filtering rules configured by you or your payment service provider.

Authenticate Payer Response
{
  "authentication": {
    "3ds2": {
      "methodCompleted": false,
      "methodSupported": "SUPPORTED"
    },
    "payerInteraction": "REQUIRED",
    "redirect": {
      "customized": {
        "3DS": {
          "acsUrl": "https://<host_name>/acs/v2/prompt",
          "cReq": "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImFhZjliNTlkLTJlMDQtNGNkNS05NDM4LTU4ZTgwYTM3MGI1YSJ9"
        }
      },
      "domainName": "<domain_name>"
    },
    "redirectHtml": "<div id=\"threedsChallengeRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <form id =\"threedsChallengeRedirectForm\" method=\"POST\" action=\"https://<host_name>/acs/v2/prompt\" target=\"challengeFrame\"> <input type=\"hidden\" name=\"creq\" value=\"eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImFhZjliNTlkLTJlMDQtNGNkNS05NDM4LTU4ZTgwYTM3MGI1YSJ9\" /> </form> <iframe id=\"challengeFrame\" name=\"challengeFrame\" width=\"100%\" height=\"100%\" ></iframe> <script>document.getElementById(\"threedsChallengeRedirectForm\").submit();</script> </div>",
    "version": "3DS2"
  },
  "order": {
    "currency": "AUD",
    "status": "AUTHENTICATION_INITIATED"
  },
  "response": {
    "gatewayCode": "PENDING",
    "gatewayRecommendation": "PROCEED_WITH_AUTHENTICATION"
  },
  "result": "PENDING",
  "sourceOfFunds": {
    "provided": {
      "card": {
        "number": "512345xxxxxx0008"
      }
    },
    "type": "CARD"
  },
  "transaction": {
    "authenticationStatus": "AUTHENTICATION_PENDING"
  },
  "version": "58"
}
Frictionless Flow

This will redirect the payer’s browser straight back to your website. You can proceed to submit a subsequent payment to the gateway. The gateway will obtain the authentication data related to the payment and will ensure that payments will only be processed where all the 3DS transaction filtering rules (configured by you or your payment service provider) have passed.

Challenge Flow

This will redirect the payer’s browser to the ACS where the issuer’s challenge UI will be presented, after which the payer will be redirected back to your web site. The following fields are returned in the callback once the payer’s browser has been returned to your website.

  • orderId
  • transactionId
  • gatewayRecommendation
  • restApiResponse

You can determine the authentication outcome using the value returned in the gatewayRecommendation field. Please note that this recommendation is only based on the 3DS transaction filtering rules configured by you or your payment service provider.

Authenticate Payer Response Fields

The fields returned in the restApiResponse depend on the flow in effect (frictionless vs challenge) and how the authentication request was initiated (authentication.channel).

For a session-authenticated request, the response is filtered to remove data that’s not related to the payer and only whitelisted fields are returned.

Advanced Integrations

The request submitted by the payer’s browser to your website on completion of the authenticatePayer() method will be parameterized allowing you to determine the authentication outcome. The individual authentication parameters, for example, authentication.3ds2.transactionStatus.data, may be useful in an advanced integration or if you have the need to provide the authentication data in a payment processed via another gateway.

Step 5: Use the Authentication Result in a Payment Operation

When the result of the authenticatePayer() method indicates that you can proceed with the payment (gatewayRecommendation=PROCEED), you may initiate an Authorize or Pay operation. In addition to the standard fields, you must provide the following fields:

  • order.id:

Provide the orderId that you supplied in the initiateAuthentication() and authenticatePayer() methods.

  • authentication.transactionId:

Provide the transactionId that you supplied in the initiateAuthentication() and authenticatePayer() methods. You do not need to include any of the fields in the authentication parameter group, as the gateway will use the authentication.transactionId to look up the authentication results that it stored when you asked it to perform authentication. The gateway will pass the required information to the acquirer.

Pay Request
URL: {host}/api/rest/version/{apiVersion}/merchant/{merchantId}/order/{orderId}/transaction/1
HTTP Method: PUT
 
{
    "apiOperation":"PAY",
    "authentication":{
        "transactionId":"{transactionId}"
    },
    "order":{
        "amount":"100",
        "currency":"AUD",
        "reference":"{orderId}"
    },
    "sourceOfFunds":{
        "provided":{ 
            "card":{ 
                "number":"{pan}",
                "expiry":{
                    "month":"5",
                    "year":"21"
                }
            }
        },
        "type":"CARD"
    },
    "transaction":{
        "reference":"{orderId}"
    }
}
	
Pay Response - 3DS2
{ 
   "authentication":{ 
      "3ds":{ 
         "acsEci":"02",
         "authenticationToken":"kHyn+7YFi1EUAREAAAAvNUe6Hv8=",
         "transactionId":"39c25b96-7bc3-4586-bee8-056479fed3af"
      },
      "3ds2":{ 
         "dsTransactionId":"39c25b96-7bc3-4586-bee8-056479fed3af",
         "protocolVersion":"2.1.0",
         "transactionStatus":"Y"
      },
      "transactionId":"249213216",
      "version":"3DS2"
   },
   "authorizationResponse":{ 
      "posData":"1605S0100130",
      "transactionIdentifier":"TidTest"
   },
   "gatewayEntryPoint":"WEB_SERVICES_API",
   "merchant":"TEST_3DS2-1",
   "order":{ 
      "amount":100.00,
      "chargeback":{ 
         "amount":0,
         "currency":"AUD"
      },
      "creationTime":"2019-10-28T05:00:27.234Z",
      "currency":"AUD",
      "id":"807a01b6-e6c8-4aa7-b8da-799bfff89496",
      "merchantCategoryCode":"1234",
      "reference":"807a01b6-e6c8-4aa7-b8da-799bfff89496",
      "status":"CAPTURED",
      "totalAuthorizedAmount":100.00,
      "totalCapturedAmount":100.00,
      "totalRefundedAmount":0.00
   },
   "response":{ 
      "acquirerCode":"00",
      "gatewayCode":"APPROVED"
   },
   "result":"SUCCESS",
   "sourceOfFunds":{ 
      "provided":{ 
         "card":{ 
            "brand":"MASTERCARD",
            "expiry":{ 
               "month":"5",
               "year":"21"
            },
            "fundingMethod":"CREDIT",
            "issuer":"<issuer>",
            "number":"512345xxxxxx0008",
            "scheme":"MASTERCARD",
            "storedOnFile":"NOT_STORED"
         }
      },
      "type":"CARD"
   },
   "timeOfRecord":"2019-10-28T05:00:27.234Z",
   "transaction":{ 
      "acquirer":{ 
         "batch":1,
         "id":"<acquirer_id>",
         "merchantId":"99554411"
      },
      "amount":100.00,
      "authenticationStatus":"AUTHENTICATION_SUCCESSFUL",
      "authorizationCode":"028941",
      "currency":"AUD",
      "frequency":"SINGLE",
      "id":"1",
      "receipt":"1908266016",
      "reference":"807a01b6-e6c8-4aa7-b8da-799bfff89496",
      "source":"INTERNET",
      "terminal":"1234",
      "type":"PAYMENT"
   },
   "version":"57"

Test your Integration

To test your integration you can use your TEST merchant profile in the Production environment.

FAQ

What exactly happens when I redirect the user?

After you redirect the user to another page in the iframe, it does a POST request to your URL.

The response puts information in the iframe.

In the Hosted Checkout case, the iframe is prompted to do a POST response to the redirect url, and the response is just the site rendered within the iframe.

The site is mimicking a single page application. Everything is rendered in an iframe, all within the page.

Factors like server-side use (by the user) will have a bearing on flow.

When you paste the htmlRedirect code in the page, it renders the iframe (you get a challenge or frictionless flow). Next, a POST request is sent to your server (redirect URL). The request contains the result of authentication (the body will have IDs like gatewayRecommendation). The transactionId linked to the authentication will be in the payment transaction, linking the two together (note that MPGS treats authentications as transactions).

Do I need to do anything special to make sure I get the 3DS liability shift?

In order to make sure you get the benefit of the liability shift promised by 3DS, you should be careful to include authentication.transactionId in the payment (this is different from the normal payment id). It is the parameter that links the authentication transaction to the payment transaction.

Do the frictionless and challenge flows use the same calls and methods?

The frictionless and challenge flows use the same calls and methods. They both go to redirect eventually. The difference is that sometimes you will go to ACS before redirect (in the challenge flow case).