Skip to content

Front-end implementation

In this section, we show the integration implementation for the front-end of the merchant application using our Sample Code.

Note

Please go through the Sample Code and implement that before continuing.

The following diagram shows the main files for the front-end, which can be found in the /resource folder in the /final project. Please check the directory tree if needed. The 3ds-web-adapter.js is our 3DS-web-adapter.

front-end files

Process 1: Initialise the Authentication

To initialise authentication, the front-end needs to:

  • Send a Initialise authentication message to the 3DS Requestor (Step. 1 and Step. 2).
  • Receive the response message and setup callback iframe (Step. 5 and Step. 6).

When a user clicks the "Continue to checkout" button in the checkout page, it will trigger the browser sending information to the 3DS-web-adapter for initialising authentication (Step. 1). This is implemented in the checkout() function at checkout.html.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
//checkout.html
function checkout() {
    ...
    $("#cardholderInfoCard").remove();
    $("#checkoutCard").removeClass("d-none");

    //move to result screen 2 seconds after
    //setTimeout(function () { window.location.href = "/auth/result"}, 2000);
    threeDSAuth(transId, cardHolderInfo, purchaseInfo);
}

The threeDSAuth() function is implemented in 3ds-web-adapter.js (Step. 2).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    //3ds-web-adapter.js
    function threeDSAuth(transId, cardHolderInfo, purchaseInfo) {

        var postData = {...}

        ....

        console.log('init authentication');
        $.ajax({
            url: '/auth/init',
            type: 'POST',
            contentType: "application/json",
            data: JSON.stringify(postData),
            success: function (data) {
                console.log('init auth returns:', data);
                $('<iframe id="threeds-container" width="0" height="0" 
                style="visibility: hidden;" 
                src="' + data.threeDSServerCallbackUrl + '"></iframe>')
                    .appendTo('.challengeContainer');
            },
            error: function () {
                alert('error');
            },
            dataType: 'json'

        });

    }

The threeDSAuth() function makes a POST request to the 3DS Requestor with url /auth/init (line 10). The object is posted in JSON format. To check the 3DS Requestor handles this request, please refer here.

Note

threeDSAuth() can be modified according to your needs and you can transfer your objects instead of cardholderInfo, purchaseInfo and transId. The data structure can be found in the API document.

After a successful response from /auth/init (Step. 5) the 3ds-web-adapter.js inserts a hidden iframe into the checkout page (Step. 6) so that the browser information can be collected by the ACS and 3DS Server using the threeDSServerCallbackUrl (Step. 7) line 16 - 19.

Info

Step. 1 to Step. 7 of the sequence diagram are implemented by the end of this process.

Process 2: Execute Authentication

To execute authentication, the front-end needs to:

  • Implement a notify_3ds_events.html.
  • Send a Execute authentication message to the 3DS Requestor (Step. 8 and Step. 9).
  • Handle the authentication result with frictionless flow or challenge flow (Step. 13, Step. 14(F) or Step. 14(C)).

The notify_3ds_events.html is used to trigger the authentication process (Step. 8). The 3DS Requestor will render html below with variables transId, callbackType and an optional param. To check back-end implementation, please refer here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!--notify_3ds_events.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>3DSecure 2.0 Authentication</title>
</head>
<body>

<form>
    <input type="hidden" id="notifyCallback" name="notifyCallback" data-th-value="${callbackName}"/>
    <input type="hidden" id="transId" name="transId" data-th-value="${transId}"/>
    <input type="hidden" id="param" name="param" data-th-value="${callbackParam}"/>
</form>

<script src="https://code.jquery.com/jquery-3.3.1.min.js"
        integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
        crossorigin="anonymous"></script>
<script>

//notify parent checkout page to proceed with rest procedures.

var callbackFn = parent[$('#notifyCallback').val()];

//callbackFn is defined in 3ds-notify handler method
if (typeof callbackFn === 'function') {
    callbackFn($('#transId').val(),$('#param').val());
}

</script>

</body>
</html>

You can see that depending on the callbackName, it will call different methods in 3ds-web-adapter.js (Step. 8). The value of callbackName should be either _onThreeDSMethodFinished or _onThreeDSMethodSkipped. An explanation of each method is below:

  • _onThreeDSMethodFinished - notifies that the 3DS method is finished and calls _doAuth(), which means browser information collection is finished.
  • _onThreeDSMethodSkipped - notifies that the 3DS method has been skipped and calls _doAuth(), which means browser information collection by the ACS is skipped.

The _doAuth() in 3ds-web-adapter will make a POST request to /auth to execute authentication (Step. 9). To check 3DS Requestor handles the request, please refer here.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
    //3ds-web-adapter.js
    function _doAuth(transId) {
        ...    
        $.post("/auth", {id: transId}).done(function (data) {
            console.log('auth returns:', data);

            if (!data) {
                alert('error');
                return;
            }

            switch (data.transStatus) {
                case "Y":
                    authSuccess(data, transId);
                    break;
                case "C":
                    startChallenge(data.challengeUrl);
                    break;
                ...
            }
    }

The _doAuth() POSTs the request to /auth (line 4) and gets the result data. It then performs different flows based on the returned transStatus (line 14 and 17).

If the transStatus is Y, it means the authentication is successful. The 3DS-web-adapter will switch to the frictionless flow and execute the authSuccess() function (Step. 14(F)) which is the next process -> Get Authentication Result.

If the transStatus is C, the 3ds-web-adapter.js will call startChallenge(), which inserts an iframe for the challenge window with src set to challengeUrl (Step. 14(C)).

1
2
3
4
5
6
7
8
9
    function startChallenge(url) {
    //remove the spinner
    $(".spinner").remove();

    //create the iframe
    $('<iframe src="'+url+'" class="h-100 w-100 border-0" id="challengeWindow" name="challengeWindow"></iframe>')
     .appendTo('.challengeContainer');

    }

Note

If you want to test the challenge scenario, follow the guide here.

You can see that iframe class has been set to h-100 and w-100, which is the bootstrap default class to implement css style of height: 100%!important and width: 100%!important respectively. This is required because the iframe needs to resize according to the content provided by the ACS. The challenge screen should look similar to the screenshot below:

result screen

Info

In the real scenario the ACS will perform complex risk-based authentication from the information obtained about the cardholder, and is not as simple as checking the purchase amount. Similarly, the authentication method will be determined and implemented by the cardholders issuing bank.

Process 3: Get Authentication Result

To get authentication result, the front-end needs to:

When the authentication result is ready, the 3DS Requestor will notify the front-end using _onAuthResult message in notify_3ds_events.html. Then, 3ds-web-adapter sends Request for authentication result request to 3DS Requestor with url /auth/result in the following diagram. To check the 3DS Requestor handles the notify_3ds_events.html message, please refer here.

1
2
3
    function _onAuthResultReady(transId) {
        //redirect to result page
        window.location.href = "/auth/result?txid=" + transId;
Finally, the browser will redirect to result.html page to show the result details of the authentication.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 <div class="col-sm-8">
     <div class="card">
         <div class="card-header">Transaction successful</div>
         <div class="card-body">
             <h4 class="card-title text-success">3D secure authentication was successful</h4>
             <p class="card-text">You may move onto authorization using the result below 
                  or you can press "Back To Home" to restart authentication process.</p>

             <dl class="row">
                 <dt class="col-sm-3">Trans Status</dt>
                 <dd class="col-sm-9" data-th-text="${result.transStatus}">Y</dd>
                 <dt class="col-sm-3">ECI</dt>
                 <dd class="col-sm-9" data-th-text="${result.eci}">eci value</dd>
                 <dt class="col-sm-3">CAVV</dt>
                 <dd class="col-sm-9" data-th-text="${result.authenticationValue}">cavv value</dd>
                 <dt class="col-sm-3">Other Info</dt>
                 <dd class="col-sm-9"></dd>
             </dl>

             <a href="/" class="btn btn-primary">Back To Home</a>
         </div>
     </div>
 </div>

The new result screen will look like the screenshot below: result screen

Success

Congratulations! You have done the front-end integration. After this process you normally move on to performing authorisation using the Transaction Status, ECI and CAVV to complete the transaction.

Whats next?

Please select the next button to learn about Back-end implementation for a 3DS Requestor.