Shopper authentication is supported for all credit and debit cards, which is handled by either 3D Secure version 1 (3DSv1) or 3D Secure version 2 (3DSv2). Both protocols are designed by the card schemes (Mastercard, Visa, Amex, and Bancontact) and supported by the Payment System.
The integration requirements between 3DSv1 and 3DSv2 are, unfortunately, significantly different. For 3DSv1 a redirect URL and parameters will be provided by the Payment System, whereas for 3DSv2 multiple URLs may be returned each requiring their own handling. See also Start Payment .
Finally, the information presented on this page is only relevant when the payment menu of CM.com is not used.
JavaScript files
For credit card payments JavaScript file(s) is needed to handle a part of the integration, which can be for starting the actual payment or handling the authentication. The complete JavaScript files can be found at the following locations.
Environment | File | Purpose |
---|---|---|
Test/Sandbox | 3dsv1.js | 3DSv1 authentication |
3dsv2_sdk_v2.js | 3DSv2 authentication | |
apple_pay_v3.js | Apple Pay (start payment) | |
google_pay_v3.js | Google Pay (start payment) | |
nca-3ds-web-sdk.js | 3DSv2 authentication | |
Production | 3dsv1.js | 3DSv1 authentication |
3dsv2_sdk_v2.js | 3DSv2 authentication | |
apple_pay_v3.js | Apple Pay (start payment) | |
google_pay_v3.js | Google Pay (start payment) | |
nca-3ds-web-sdk.js | 3DSv2 authentication |
JavaScript functions
Function | Purpose |
---|---|
window.nca3DSWebSDK | loaded by nca-3ds-web-sdk.js |
window.showAuthenticationFrame() | create an iframe that holds the authentication screen for the consumer (do not reuse the iframe for 3DS method) |
window.pollOrderStatus() | poll the status of the order |
window.showPaymentCanceled() | show a message that the authentication or authorization failed |
3DSv1 (Obsolete)
For 3Dsv1 authentication only a redirect has to be performed in the browser towards the issuing bank of the card. The Payment System returns the URL and any additional parameters as part of the start payment response. The purpose of the URL element is set to REDIRECT
and only one URL needs to be handled. The shopper returns to the webshop after the authentication result has been processed by the Payment System.
3DS Version 1 is being phased out and is no longer available after July 1, 2024.
Sample Script
Below is an example JavaScript that handles the 3DSv1 authentication request, after the initial payment request has been performed.
/**
* Redirect the shopper for 3DSv1 authentication.
* @param authenticationUrl The authentication URL.
* @param postParameters The parameters to the post request.
*/
function redirectForThreeDsOneAuthentication(authenticationUrl, postParameters) {
var form = document.createElement('form');
document.body.appendChild(form);
form.method = 'post';
form.action = authenticationUrl;
for (var name in postParameters) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = name;
input.value = postParameters[name];
form.appendChild(input);
}
form.submit();
}
3DSv2
For 3DS authentication one or two URLs are returned as part of the start payment response. There are possible URLs, which need to be loaded into an i-frame using an HTTP-POST request:
- The Issuer/ACS Method URL, indicated with the purpose
HIDDEN_IFRAME
. This URL is used by the card issuer to gather device/browser information of the shopper.
This URL is optionally returned in the start-payment response, but if it is present then it must be handled. - The authentication URL, indicated with the purpose
IFRAME
. This URL is used to start the actual authentication with the shopper.
The diagram below shows the interaction between the shopper's browser, the Payment System, and the issuer, in case that the shopper must authenticate (challenge flow).
A frictionless flow, when the shopper does not have to authenticate, is as followed:
Note, that it is up to the issuer to decide if the authentication flow will be challenged or not. The exception to this is the initial payment for a subscription, which will always be challenged.
Request
Field | Type | M | Description |
---|---|---|---|
force_authentication | boolean | O | Boolean value to indicate if authentication must be forced. Default is false . |
browser_info | Block | M | Information about the browser. |
- ip_address | String(1, 255) | O | The IP address of the shopper. If not supplied, then the Payment System uses the IP of the request. |
- java_enabled | boolean | M | Boolean value to indicate if Java is enabled in the browser. The call navigator.javaEnabled() can be used to determine the value. |
- java_script_enabled | boolean | M | Boolean value to indicate if JavaScript/ECMAScript is enabled. This should always be true . |
- language | String(1, 16) | O | The language as reported by the browser, following the format as specified in IETF BCP47. The call navigator.language can be used for the value. The default is en-EN . |
- color_depth | Number(1, 48) | O | The color depth of the screen. Defaults to 24bits. |
- screen_height | Number(1, 999999) | M | The screen height. |
- screen_width | Number(1, 999999) | M | The screen width. |
- time_zone_offset | Number(-9999, 9999) | O | The time offset in the browser compared to UTC in minutes. The call new Date().getTimezoneOffset() can be used to determine the value. |
challenge_window_size | Enum(2) | M | The size of the challenge window. |
shopper_info | Block | O | Additional information about the shopper. |
- shopper_name | String(1, 50) | M | The name of the shopper as on the card. |
The possible values for the field challenge_window_size
are (width x height in pixels):
01
: 250 x 40002
: 390 x 40003
: 500 x 60004
: 600 x 40005
: 100% of the available screen (i-frame) size.
Response
The response has the following fields, similar to the start payment response:
Field | Type | M | Description |
---|---|---|---|
result | Enum(64) | M | The authentication result. |
urls | Block[] | C | Required for result states CHALLENGE and SOFT_DECLINED. |
url | Block | M | The redirect details for the shopper. |
- purpose | Enum(64) | M | The purpose of this URL. |
- method | Enum(16) | M | The HTTP method to be used, either "GET" or "POST". |
- url | Url | M | The URL the shopper must be redirected to. |
- order | Number(1,10) | M | The order in which the URLs must be displayed or handled. |
- parameters | Map | O | Map with parameter name/values pairs for the body of the redirect request. |
error | Block | C | The details of the error. |
- message_key | Enum(64) | M | The message key for the error. |
- message | String(1, 255) | O | The details of the error, if any additional information is available. |
The URLs need to be processed in the order as specified by the field order
.
The field result
returns one of the following values:
Result | Description |
---|---|
AUTHORIZED | The payment is authorized. |
CHALLENGE | The shopper must be authenticated before authorization can occur. Handle the URLs as specified in the response. |
SOFT_DECLINE | The authorization was declined, but can be re-attempted after authentication of the shopper. Handle the URLs as specified in the response. |
ERROR | Some intermediate system error occurred. |
CANCELED | The shopper authentication failed, risk check failure, or authorization failed. |
For the field purpose
the following values are possible:
Purpose | Description and required actions |
---|---|
REDIRECT | Redirect the shopper to the specified URL using the given method and parameters . |
HIDDEN_IFRAME | The URL must be loaded in an i-frame that is hidden from the shopper. The size of the i-frame can be 0x0 or 1x1 pixels. |
IFRAME | The URL must be loaded in an i-frame that is visible to the shopper. The i-frame will be used by the issuer to display the authentication page. |
In case of an 'HIDDEN_IFRAME' the data has to be sent via a basic HTML-form. A basic HTML-form is needed to ensure that the HTTP-POST request is a simple request according to Cross-Origin Resource Sharing (CORS). This avoids the browser from doing a pre-flight request (HTTP-OPTIONS request), as some issuers may or may not handle the preflight-request properly.
The same applies also in case the purpose is 'IFRAME'.
Finally, the field 'message_key' has one of the following possible values:
Message Key | Description |
---|---|
payment_authentication_canceled | The authentication was canceled by the shopper. The payment is canceled. |
payment_3dsv2_authentication_rejected | The authentication was rejected by the issuing bank. The payment is canceled. |
payment_processing_error | There was a problem processing the authentication request or authorization request. The payment is canceled. |
mainView_canceledDialogText | There was an unknown error during authentication. The payment is canceled. |
Note: Additional message keys can be added in the future.
Strong Customer Authentication (SCA) Exemptions
It is possible to apply an SCA exemption for certain credit card payments. In these cases 3DSv1 or 3DSv2 is not used to authenticate the shopper, but the original payment is used to validate that the shopper was authenticated.
Test Card Numbers
Below are several card numbers for each scheme and/or payment method to test and/or validate the 3DSv2 integration.
Each number must be prefixed to get a complete card number:
- for American Express:
3411 1111 111
; - for Visa & VPay:
4111 1111 1111
; - for Mastercard:
5555 5555 5555
; - for Bancontact & Maestro:
6703 9999 8800
.
Scenario | Scheme | Last Four Digits | Method URL | Authentication Scenario |
---|---|---|---|---|
American Express | 1111 | Yes | Standard test card number; authentication required. | |
51 | 1517 | No | Frictionless, no authentication required. | |
52 | 1525 | No | Card is soft-declined during first authorization attempt. | |
53 | 1533 | No | Card is always soft-declined. | |
55 | 1558 | No | Card is not enrolled for 3DSv2 and with reason code 13. | |
56 | 1566 | No | Unknown error during authentication. | |
57 | 1574 | No | Card is rejected at authentication. | |
59 | 1590 | No | Card not supported by the issuer. | |
61 | 1616 | N/A | 3RI with decoupled successful authentication (5 seconds delay). | |
62 | 1624 | N/A | 3RI with decoupled failed authentication (5 seconds delay). | |
65 | 1657 | N/A | 3RI decoupled authentication not supported, authentication success. | |
66 | 1665 | N/A | 3RI decoupled authentication not supported, authentication failed. | |
wxyz | Depends | Any other 4 digits not mentioned; authentication required. | ||
MasterCard | 4444 | Yes | Standard test card number; authentication required. | |
51 | 4519 | No | Frictionless, no authentication required. | |
52 | 4527 | No | Card is soft-declined during first authorization attempt. | |
53 | 4535 | No | Card is always soft-declined. | |
54 | 4543 | No | Card is not enrolled for 3DSv2 and with reason code 82. | |
55 | 4550 | No | Card is not enrolled for 3DSv2 and with reason code 13. | |
56 | 4568 | No | Unknown error during authentication. | |
57 | 4576 | No | Card is rejected at authentication. | |
59 | 4592 | No | Card not supported by the issuer. | |
61 | 4618 | N/A | 3RI with decoupled successful authentication (5 seconds delay). | |
62 | 4626 | N/A | 3RI with decoupled failed authentication (5 seconds delay). | |
65 | 4659 | N/A | 3RI decoupled authentication not supported, authentication success. | |
66 | 4667 | N/A | 3RI decoupled authentication not supported, authentication failed. | |
wxyz | Depends | Any other 4 digits not mentioned; authentication required. | ||
Visa | 1111 | Yes | Standard test card number; authentication required. | |
51 | 1517 | No | Frictionless, no authentication required. | |
52 | 1525 | No | Card is soft-declined during first authorization attempt. | |
53 | 1533 | No | Card is always soft-declined. | |
55 | 1558 | No | Card is not enrolled for 3DSv2 and with reason code 13. | |
56 | 1556 | No | Unknown error during authentication. | |
57 | 1574 | No | Card is rejected at authentication. | |
59 | 1590 | No | Card not supported by the issuer. | |
61 | 1616 | N/A | 3RI with decoupled successful authentication (5 seconds delay). | |
62 | 1624 | N/A | 3RI with decoupled failed authentication (5 seconds delay). | |
65 | 1657 | N/A | 3RI decoupled authentication not supported, authentication success. | |
66 | 1665 | N/A | 3RI decoupled authentication not supported, authentication failed. | |
wxyz | Depends | Any other 4 digits not mentioned; authentication required. | ||
Bancontact | 1111 | Yes | Standard test card number; authentication required. | |
51 | 1517 | No | Frictionless, no authentication required. | |
52 | 1525 | No | Card is soft-declined during first authorization attempt. | |
53 | 1533 | No | Card is always soft-declined. | |
55 | 1558 | No | Card is not enrolled for 3DSv2 and with reason code 13. | |
56 | 1556 | No | Unknown error during authentication. | |
57 | 1574 | No | Card is rejected at authentication. | |
59 | 1590 | No | Card not supported by the issuer. | |
61 | 1616 | N/A | 3RI with decoupled successful authentication (5 seconds delay). | |
62 | 1624 | N/A | 3RI with decoupled failed authentication (5 seconds delay). | |
65 | 1657 | N/A | 3RI decoupled authentication not supported, authentication success. | |
66 | 1665 | N/A | 3RI decoupled authentication not supported, authentication failed. | |
wxyz | Depends | Any other 4 digits not mentioned; authentication required. |
The column 'Scenario' can be used for in communication with support if there are any (integration) questions.
The column 'Method URL' indicates if an ACS/3DS Method URL will be part of the start payment response.
The following OTP values can be used, when presented with an authentication request form:
OTP value | 3DS Status | Result |
---|---|---|
1234 | Y | Authentication success |
1111 | N | Authentication failed |
2222 | R | Authentication rejected |
3333 | U | Authentication could not be performed |
4444 | A | Authentication attempted (not authenticated, but attempt proof provided) |
The values 1234
and 4444
are success scenarios, while the other values lead to a failed payment attempt.
Sample Script
Below is an example JavaScript that handles the 3DSv2 authentication request, after the initial payment request has been performed. This includes the handling of a payment that is directly authorized as well as for which a challenge is requested.
/**
* <em>SAMPLE SCRIPT for performing 3DS v2 authentication</em>
* <p>
* Executes the 3DS v2 ACS method URL of the browser and authentication instructions for the shopper.
*
* This function performs two things:
* <ol>
* _It loads the ACS method URL, and after loading_
* _Executes the authentication call to CM Payments to authenticate the shopper._
* </ol>
*
* The ACS Method URL is performed in an i-frame, hidden from the shopper, by posting the <code>acsMethodData</code>
* to the <code>acsMethodURl</code>. The result is processed by the ACS and a notification of that is
* directly received by CM payments from the ACS.
* <br/>
* Shopper authentication is performed by posting the <code>authenticationData</code> to the authentication URL
* (<code>authenticationUrl</code>). For further details see handleThreeDsAuthentication().
* <p>
* For additional information see EMVCo 3DS spec 2.2.0 chapters '3.3 - Browser-based Requirements' and chapter
* '5.8 - Browser-based Message Handling'.
*
* @param acsMethodUrl The ACS method URL.
* @param acsMethodData The ACS method data.
* <br/>The data should be posted as is using the parameter name 'threeDSMethodData'.
* @param authenticationUrl The authentication URL.
* @param authenticationData The authentication data.
* <br/>The authentication data should be amended with additional information about the
* browser and shopper.
* @param forceAuthentication <code>true</code>, if the authentication of the shopper must be forced.
* Otherwise, <code>false</code>, it is left to Payment System and/or issuer.
*/
function performThreeDsAuthentication(acsMethodUrl, acsMethodData,
authenticationUrl, authenticationData,
forceAuthentication) {
if (!authenticationUrl || !authenticationData) {
throw Error('Not all ACS Authentication parameters provided');
}
if (!acsMethodUrl) {
// No ACS method URL, so can skip that part. Directly authenticate the shopper.
handleThreeDsAuthentication(authenticationUrl, authenticationData, forceAuthentication);
} else {
if (!acsMethodData) {
throw Error('Not all ACS 3DS method parameters provided');
}
window.nca3DSWebSDK.createIframeAndInit3DSMethod(acsMethodUrl, acsMethodData,
'threeDSMethodIFrame', document.body,
new function () {
handleThreeDsAuthentication(authenticationUrl,
authenticationData,
forceAuthentication)
});
}
}
/**
* Perform the authentication request at CM Payments. The request is then forwarded to the ACS for evaluation.
*
* <p>
* The parameter <code>authenticationData</code> is used to provide additional authentication and has the
* following structure:
* <pre>
* {
* "browser_info" : { ... },
* "shopper_info" : { ... }
* }
* </pre>
* The additional data is used to provide additional information about the shopper that was not provided in the original
* create-order API request or if more precise information is available. The data is optional, but may allow the shopper
* to experience the frictionless flow, in which case the shopper does not have to authenticate.
*
* @param authenticationUrl The authentication URL
* @param authenticationData The additional authentication data
* @param forceAuthentication <code>true</code>, if the authentication of the shopper must be forced.
* Otherwise, <code>false</code>, it is left to Payment System and/or issuer.
*/
function handleThreeDsAuthentication(authenticationUrl, authenticationData, forceAuthentication) {
let xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState === 4) {
if (this.status === 200) {
/**
* The response structure is similar to the REST API start response; the error component is added to
* present a more detailed error message to the shopper. For sake of brevity only the used fields are
* mentioned here.
*
* <pre>
* "result" : <"CHALLENGE" | "AUTHORIZED" | "SOFT_DECLINE" | "ERROR" | "CANCELED"> (mandatory)
* "url" : [ {
* "url" : "some URL", (mandatory)
* "order" : 1, (mandatory)
* "purpose" : <"REDIRECT" | "IFRAME" | "HIDDEN_IFRAME">, (mandatory)
* "parameters" : [{key, value}]
* },
* ...
* ],
* "error" : {
* "message" : "some message", (conditional, if result === ERROR or result === CANCELED)
* "message_key : "some key" (conditional, if result === ERROR or result === CANCELED)
* }
* </pre>
*/
let response = JSON.parse(this.responseText);
if (response.result === 'CHALLENGE') {
let redirectUrlData = findUrlWithPurpose(response.urls, 'REDIRECT');
if (redirectUrlData) {
redirectForThreeDsOneAuthentication(redirectUrlData.url, redirectUrlData.parameters);
} else {
/* We have some knowledge of the returned data here. All the URLs require POST and the parameter
* names are known. The parameter name is 'creq', which is the same as what is required in the form
* that needs to be posted to the ACS (see also EMVco 3DSv2 specification; table A.3 - CReq/CRes POST data).
*/
let challengeUrlData = findUrlWithPurpose(response.urls, 'IFRAME');
// The authentication frame is created and maintained by the OPC menu. The i-frame itself must have
// a name/identifier.
let authenticationFrame = window.showAuthenticationFrame();
window.nca3DSWebSDK.init3DSChallengeRequest(challengeUrlData.url,
challengeUrlData.parameters['creq'],
authenticationFrame);
}
} else if (response.result === 'SOFT_DECLINE') {
/* The payment authorization was soft-decline by the acquirer/issuer; the payment can be completed
* if the shopper is authenticated. This requires a restart of the authentication process, so the
* function 'performThreeDsAuthentication' is called again.
*
* We have some knowledge of the returned data here. All the URLs require POST and the parameter
* names are known. The ACS method is passed along under 'threeDSMethodData' and must be posted
* using the same (parameter) name (see also EMVco 3DSv2 specification; table A.2 - 3DS Method Data).
*/
let acsMethodUrlData = findUrlWithPurpose(response.urls, 'HIDDEN_IFRAME');
let methodUrl = acsMethodUrlData === null ? null : acsMethodUrlData.url;
// The parameter is named 'threeDSMethodData'.
let methodData = acsMethodUrlData === null ? null : acsMethodUrlData.parameters['threeDSMethodData'];
// There is always an authentication URL and no parameter data
let authenticationUrlData = findUrlWithPurpose(response.urls, 'IFRAME');
let authUrl = authenticationUrlData.url;
performThreeDsAuthentication(methodUrl, methodData, authUrl, '{}', true);
} else if (response.result === 'AUTHORIZED') {
// Payment is authorized, need to wait for the order status to be updated.
window.pollOrderStatus();
} else {
// No need to poll the status, show the error message
window.showPaymentCanceled(response.error.message_key, response.error.message);
}
} else {
// Show the payment canceled dialog
window.showPaymentCanceled('payment_processing_error', this.statusText);
}
}
};
xhttp.open('POST', authenticationUrl, true);
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.setRequestHeader('Accept', 'application/json');
/* Add any additional browser information for the authentication request. The user-agent and browser-accept header
* are retrieved from the request itself that is retrieved by the Payment system; so there is no need to specify
* those.
*
* If a soft-decline is being handled, then the field 'force_authentication' is required. This field is passed along
* as part of the initial authentication/authorization result as well. In this sample script, that particular
* information is ignored and the value is directly set based on the passed-in parameters.
*/
let data = JSON.parse(authenticationData);
data.force_authentication = forceAuthentication;
data.browser_info = {};
data.browser_info.java_enabled = navigator.javaEnabled();
/*always enabled*/
data.browser_info.java_script_enabled = true;
data.browser_info.language = navigator.language;
data.browser_info.color_depth = screen.colorDepth;
data.browser_info.screen_height = screen.height;
data.browser_info.screen_width = screen.width;
data.browser_info.time_zone_offset = new Date().getTimezoneOffset();
data.browser_info.challenge_window_size = '05';
xhttp.send(JSON.stringify(data));
}
/**
* Helper logic to search for a particular URL with a specific purpose.
*
* @param urls The urls for 3DSv1 or 3DSv2 authentication.
* @param purpose The purpose of URL.Can be 'REDIRECT', 'HIDDEN_IFRAME' or 'IFRAME'.
*
* @return the URL with given purpose.
*/
function findUrlWithPurpose(urls, purpose) {
for (let url of urls) {
if (url.purpose === purpose) {
return url;
}
}
return null;
}