Challenge Template Configuration

Challenge template

When initiating an authentication request to the NDM simulator, if the card is configured for Challenge flow, then the NDM simulator will set the acsURL field to be handled by the NDM Simulator Challenge handler.

The Netcetera Demo Merchant Simulator provides a pre-defined HTML template that is returned when initiating a Challenge Request to the simulated ACS Challenge handler. The challenge screen and the template source are displayed below:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>NDM Simulator Challenge</title>
</head>
<body style="margin: 0; padding: 8px;">
<main>
    <div>
        <header>
            <span class="logo"></span>
        </header>
        <div class="content">
            <form id="mainForm" method="post" action="%otpValidationUrl$">
                <input id="threeDSSTransId" type="text" name="threeDSSTransId" class="hidden" value="%threeDSSTransId$">
                <h1>Challenge Form</h1>
                <div class="transaction-details">
                    <ul>
                        <li>
                            <span class="ui-messages-summary">Cardholder Account Number: </span>
                            <span class="ui-messages-detail"> %acctNumber$ </span>
                        </li>
                        <li>
                            <span class="ui-messages-summary">Merchant Name: </span>
                            <span class="ui-messages-detail">%merchantName$</span>
                        </li>
                        <div id="purchaseDetails">
                            <li>
                                <span class="ui-messages-summary">Purchase Amount: </span>
                                <span class="ui-messages-detail">%purchaseAmount$</span>
                            </li>
                            <li>
                                <span class="ui-messages-summary">Purchase Date: </span>
                                <span class="ui-messages-detail">%purchaseDate$</span>
                            </li>
                        </div>
                    </ul>
                </div>
 
 
                <div class="explainText">Please enter the sent OTP Code</div>
                <dt><label for="otp">Code</label></dt>
                <dd><input id="otp" type="text" name="otp" maxlength="10" onkeyup="checkOtp()" onblur="checkOtp()"></dd>
                <footer>
                    <button type="submit" class="btn btn-secondary" id="cancel" name="challengeCancel">Cancel</button>
                    <button type="submit" class="btn btn-primary" id="sendOtp" disabled="">Pay</button>
                </footer>
            </form>
        </div>
    </div>
</main>
 
<script>
    var messageCategory = "%messageCategory$";
    if (messageCategory === "02") {
        document.getElementById('purchaseDetails').setAttribute("class", "hidden");
    }
    function checkOtp() {
        var otp = document.getElementById("otp");
        var submitOtp = document.getElementById("sendOtp");
        var validInputRegex = /^[a-zA-Z0-9]+$/;
        submitOtp.disabled = !validInputRegex.test(otp.value);
    }
</script>
 
<style>
 
    header {
        background-color: #458962;
        color: white;
    }
 
    ul {
        list-style-type: none;
    }
 
    .ui-messages-summary {
        font-weight: bold;
    }
 
    .hidden {
        visibility: hidden;
        position: absolute;
    }
 
    .logo {
        padding-top: 2%;
        background: no-repeat left center url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjxzdmcgd2lkdGg9IjEyM3B4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCAxMjMgNDAiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+DQogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCA1MS4xICg1NzUwMSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+DQogICAgPHRpdGxlPkdyb3VwPC90aXRsZT4NCiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4NCiAgICA8ZGVmcz48L2RlZnM+DQogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+DQogICAgICAgIDxnIGlkPSJHcm91cCIgZmlsbD0iI0ZGRkZGRiI+DQogICAgICAgICAgICA8cGF0aCBkPSJNMTA5LjcyNDAyMSw5LjA4OTE4MTgyIEwxMDQuNTg0NzA2LDkuMDg5MTgxODIgQzEwMS41NzI5NTcsOS4wODkxODE4MiA5OC45NTc5NTY5LDkuODM4Njc2NzcgOTcuMDExNzYxOSwxMS4zNzE2MDYxIEM5NC45NzkxMzIzLDkuODM4Njc2NzcgOTIuMDk4NDUyMSw5LjA4OTE4MTgyIDg4LjI0NTAyODUsOS4wODkxODE4MiBMODMuMTA1NzEzNSw5LjA4OTE4MTgyIEM3Ni41Njg1NjcyLDkuMDg5MTgxODIgNzEuOTAwMzkxNCwxMi42MDI2MTYyIDcxLjkwMDM5MTQsMjAuMDQwMjkyOSBMNzEuOTAwMzkxNCwzNy43NTAyOTI5IEM3MS45MDAzOTE0LDM4LjIxNjk1OTYgNzIuMzY0NDQ1OSwzOC42ODI5MTkyIDcyLjgzMjA0MjgsMzguNjgyOTE5MiBMNzguNDM3NTM3OCwzOC42ODI5MTkyIEM3OC45MDUxMzQ3LDM4LjY4MjkxOTIgNzkuMzcyMDIzMSwzOC4yMTY5NTk2IDc5LjM3MjAyMzEsMzcuNzUwMjkyOSBMNzkuMzcyMDIzMSwyMC41MDYyNTI1IEM3OS4zNzIwMjMxLDE3LjcxMTIwMiA4MC43Njk4NTQ1LDE1Ljg0NjY1NjYgODQuMDM5NDkwMywxNS44NDY2NTY2IEw4Ni44NDI5NDYzLDE1Ljg0NjY1NjYgQzkyLjQ0NTYwNzMsMTUuODQ2NjU2NiA5My4zODAwOTI2LDE3LjI0NTI0MjQgOTMuMzgwMDkyNiwyMS40Mzk1ODU5IEw5My4zODAwOTI2LDM3Ljc1MDI5MjkgQzkzLjM4MDA5MjYsMzguMjE2OTU5NiA5My44NDY5ODExLDM4LjY4MjkxOTIgOTQuMzEzODY5NSwzOC42ODI5MTkyIEw5OS45MTY1MzA1LDM4LjY4MjkxOTIgQzEwMC4zODM0MTksMzguNjgyOTE5MiAxMDAuODUxMDE2LDM4LjIxNjk1OTYgMTAwLjg1MTAxNiwzNy43NTAyOTI5IEwxMDAuODUxMDE2LDIxLjQzOTU4NTkgTDEwMC44NTEwMTYsMjAuNTA2MjUyNSBDMTAwLjg1MTAxNiwxNy43MTEyMDIgMTAyLjI1MjM5LDE1Ljg0NjY1NjYgMTA1LjUxODQ4MywxNS44NDY2NTY2IEwxMDguMzIxOTM5LDE1Ljg0NjY1NjYgQzExMy45MjQ2LDE1Ljg0NjY1NjYgMTE0Ljg1OTA4NSwxNy4yNDUyNDI0IDExNC44NTkwODUsMjEuNDM5NTg1OSBMMTE0Ljg1OTA4NSwzNy43NTAyOTI5IEMxMTQuODU5MDg1LDM4LjIxNjk1OTYgMTE1LjMyNTk3NCwzOC42ODI5MTkyIDExNS43OTI4NjIsMzguNjgyOTE5MiBMMTIxLjM5NjIzMiwzOC42ODI5MTkyIEMxMjEuODQxODY2LDM4LjY4MjkxOTIgMTIyLjMzMDAwOSwzOC4yMTY5NTk2IDEyMi4zMzAwMDksMzcuNzUwMjkyOSBMMTIyLjMzMDAwOSwyMS40Mzk1ODU5IEMxMjIuMzMwMDA5LDEzLjA1MDg5OSAxMTguNTk2MzE4LDkuMDg5MTgxODIgMTA5LjcyNDAyMSw5LjA4OTE4MTgyIiBpZD0iRmlsbC01MCI+PC9wYXRoPg0KICAgICAgICAgICAgPHBhdGggZD0iTTU4LjcwMzEwNjYsMjcuNTgyODI4MyBDNTcuNDIyMTc0NSwzMS4yNzMwMzAzIDU0LjA3MjQ4MDMsMzMuNzUzNDM0MyA1MC4zNjc4Mzc2LDMzLjc1MzQzNDMgQzQ1LjQ2NzI4MDQsMzMuNzUzNDM0MyA0MS40Nzk5NTQxLDI5LjUzMjIyMjIgNDEuNDc5OTU0MSwyNC4zNDM3Mzc0IEM0MS40Nzk5NTQxLDE5LjE1NDU0NTUgNDUuNDY3MjgwNCwxNC45MzMzMzMzIDUwLjM2NzgzNzYsMTQuOTMzMzMzMyBDNTUuMjY4Mzk0OCwxNC45MzMzMzMzIDU5LjI1NTcyMTEsMTkuMTU0NTQ1NSA1OS4yNTU3MjExLDI0LjM0MzczNzQgQzU5LjI1NTcyMTEsMjUuMTI4NTg1OSA1OS4xNTM3LDI1LjkzNjc2NzcgNTguOTUyNDkxNiwyNi43NDM1MzU0IEw1OC45MzEyMzcyLDI2LjgzMDUwNTEgQzU4Ljg4MzA2MDYsMjcuMDE1MDUwNSA1OC44MzI3NTg1LDI3LjE5ODE4MTggNTguNzczOTU0NiwyNy4zNzg0ODQ4IEw1OC43NzM5NTQ2LDI3LjM3OTE5MTkgTDU4LjcwMzEwNjYsMjcuNTgyODI4MyBaIE01OC45NDI1NzI5LDAgTDU4Ljk0MjU3MjksMTEuNDM4OTg5OSBDNTguMjQ0NzE5OSwxMC45MTc4Nzg4IDU3LjQ2OTY0MjcsMTAuNDY0NjQ2NSA1Ni42MzAwOTM3LDEwLjA4Nzc3NzggQzU0Ljg2Mzg1MjcsOS4yOTUxNTE1MiA1Mi44MjkwOTc3LDguODkzNTM1MzUgNTAuNTgxMDkwMiw4Ljg5MzUzNTM1IEM0NS43NTg0NjU4LDguODkzNTM1MzUgNDEuODQyNjk2LDEwLjM0Nzk3OTggMzguOTQxNDY5OCwxMy4yMTU4NTg2IEMzNi4wNzU2Njc2LDE2LjA0ODM4MzggMzQuNjIzMjgzMywxOS45NTI4MjgzIDM0LjYyMzI4MzMsMjQuODIxNzE3MiBDMzQuNjIzMjgzMywyOS4wODYwNjA2IDM2LjEwNDAwNjgsMzIuNjM5MDkwOSAzOS4wMjM2NTM1LDM1LjM4MzIzMjMgQzQxLjk2NDU1NDYsMzguMTQ4NTg1OSA0NS42NDE1NjY1LDM5LjU1MDcwNzEgNDkuOTUxOTU5OCwzOS41NTA3MDcxIEM1Mi41NTI3OTA0LDM5LjU1MDcwNzEgNTQuNzc4MTI2NiwzOS4xNDU1NTU2IDU2LjU2NDkxMzUsMzguMzQ1MTUxNSBDNTcuNTM2OTQ4MywzNy45MDg4ODg5IDU4LjQ2MDA5NzksMzcuMzI2OTY5NyA1OS4zMjAxOTI4LDM2LjYwNzg3ODggTDU5LjMyMDE5MjgsMzguNzAxNTE1MiBMNjUuODQ2MDAzNSwzOC43MDE1MTUyIEw2NS44NDYwMDM1LDAgTDU4Ljk0MjU3MjksMCBaIiBpZD0iRmlsbC00NCI+PC9wYXRoPg0KICAgICAgICAgICAgPHBhdGggZD0iTTE3LjI3OTEyMjQsOS4wODkxODE4MiBMMTEuMjA4MTU2LDkuMDg5MTgxODIgQzQuNjcwMzAxMTUsOS4wODkxODE4MiAwLDEyLjYwMDQ5NDkgMCwyMC4wNDAyOTI5IEwwLDM3Ljc1MSBDMCwzOC4yMTY5NTk2IDAuNDY3NTk2ODk5LDM4LjY4MjkxOTIgMC45MzUxOTM3OTgsMzguNjgyOTE5MiBMNi41Mzg1NjMzMSwzOC42ODI5MTkyIEM3LjAwNTQ1MTczLDM4LjY4MjkxOTIgNy40NzIzNDAxNSwzOC4yMTY5NTk2IDcuNDcyMzQwMTUsMzcuNzUxIEw3LjQ3MjM0MDE1LDIwLjUwNjk1OTYgQzcuNDcyMzQwMTUsMTcuNzEwNDk0OSA4Ljg3MzAwNTQsMTUuODQ2NjU2NiAxMi4xNDE5MzI4LDE1Ljg0NjY1NjYgTDE1Ljg3Nzc0ODYsMTUuODQ2NjU2NiBDMjEuNDgxODI2NiwxNS44NDY2NTY2IDIyLjQxNTYwMzUsMTcuMjQ0NTM1NCAyMi40MTU2MDM1LDIxLjQzODg3ODggTDIyLjQxNTYwMzUsMzcuNzUxIEMyMi40MTU2MDM1LDM4LjIxNjk1OTYgMjIuODgzMjAwNCwzOC42ODI5MTkyIDIzLjM0OTM4MDMsMzguNjgyOTE5MiBMMjguOTU0MTY2OCwzOC42ODI5MTkyIEMyOS4zOTc2NzU0LDM4LjY4MjkxOTIgMjkuODg3MjM1MSwzOC4yMTY5NTk2IDI5Ljg4NzIzNTEsMzcuNzUxIEwyOS44ODcyMzUxLDIxLjQzODg3ODggQzI5Ljg4NzIzNTEsMTMuMDUwODk5IDI2LjE1MjEyNzgsOS4wODkxODE4MiAxNy4yNzkxMjI0LDkuMDg5MTgxODIiIGlkPSJGaWxsLTQ3Ij48L3BhdGg+DQogICAgICAgIDwvZz4NCiAgICA8L2c+DQo8L3N2Zz4=');
        display: inline-block;
        background-size: contain;
        margin: 0 1rem 0 1rem;
        width: 90px;
        min-height: 30px;
    }
 
    dd, dt {
        display: inline-block;
        font-size: 20px;
        margin: 24px;
    }
 
    input[type="text"] {
        border: 1px solid #e4e4e4;
        border-radius: 2rem;
        font-weight: 600;
        padding: .5rem 1rem;
        line-height: 1;
        max-width: 100%;
        text-align: center;
        width: 10rem;
        margin-bottom: .25rem;
        font-size: 15px;
    }
 
    .btn {
        cursor: pointer;
        padding: .5rem 2rem;
        font-weight: 600;
        line-height: 1;
        letter-spacing: .05rem;
        margin-right: .5rem;
        border: 2px solid #458962;
        border-radius: 1rem;
    }
 
    .btn-primary {
        color: #fff;
        background-color: #458962;
    }
 
    .btn-secondary {
        background-color: #fff;
        color: #458962;
    }
 
    footer {
        font-size: 20px;
    }
 
    button:disabled {
        background: darkseagreen;
        border-color: darkseagreen;
    }
 
    .explainText {
        font-size: 20px;
        margin-bottom: 10px;
    }
 
    h1 {
        display: block;
        font-weight: bold;
        color: #9a9a9a;
    }
 
    .content {
        position: absolute;
        height: auto;
    }
</style>
</body>
</html>

Custom Challenge Template

The NDM Simulator can be also configured to provide a custom Challenge form. This can be configured via the ds-simulator-config.creq-form.template-location configuration property in the NDM Simulator configuration properties.

In order for the NDM Simulator to properly handle challenge, the customized challenge template must contain the following placeholders:

  • A form with method POST whose action has value of "%otpValidationUrl$", like:
    $ <form method="POST" action="%otpValidationUrl$">

    in order for the NDM Simulator to fill the OTP validation URL to a proper endpoint for validating the entered OTP.

  • An input field inside the form with value of "%threeDSSTransId$", like:
    $ <input value="%threeDSSTransId$">

    in order for the NDM Simulator to fill the 3DS Server Transaction ID and later on when validating the OTP to identify the transaction.

  • An input field inside the form with name "otp" (for the One Time Password), like:
    $ <input name="otp">

    in order for the NDM Simulator to handle the entered Challenge data.

For handling challenge cancel, the custom challenge template should include additional submit button to the form with name 'challengeCancel', like:

$ <button type="submit" name="challengeCancel">Cancel</button>

Additionally, there is an option to include the following placeholders in the customized template, in order to provide details about the current transaction:

  • %acctNumber$ - the cardholder account number
  • %merchantName$ - the merchant name
  • %purchaseAmount$ - the purchase amount
  • %purchaseDate$ - the purchase date

The NDM Simulator will inject values into them retrieved from the current transaction.