Important We have released a new version. Documentation for our latest version can be found [here](/products/3ds/). **Last updated**: 22 April 2025 | [**Change log**](/products/3ds/changelog/) # Challenge Display and Verification If the authentication response `outcome` is `challenged` and the `authentication.version` is `2.x.x` (3DS2) you can use the SDK to provide the improved [3DS2 Challenge display](#3ds2-challenge-display) for mobile devices. If the `authentication.version` is `1.x.x` (3DS1) you must follow the [3DS1 Challenge display](#3ds1-challenge-display). The integration more closely follows the steps for web. ## 3DS2 Challenge display If the `authentication.version` is `2.x.x` you will need the following values from the authentication response to use in the SDK. | Access Name | Value from | Cardinal SDK Name | | --- | --- | --- | | `challenge.reference` | authentication response | `transactionId` | | `challenge.payload` | authentication response | `payload` | The Access 3DS API will be periodically tested against the latest version of the Cardinal SDK. Current tested Cardinal SDK version: `v2.2.5` ### SDK challenge display: - [Android](https://cardinaldocs.atlassian.net/wiki/spaces/CMSDK/pages/1998914544/Handle+the+Centinel+Lookup+Response+and+SDK+Handle+the+Challenge+UI+-+Android+-+V+2.2.5) - [iOS](https://cardinaldocs.atlassian.net/wiki/spaces/CMSDK/pages/2005696790/Handle+the+Centinel+Lookup+Response+and+SDK+handle+the+Challenge+UI+-+iOS+-+V+2.2.5) ### Customize Challenge Interface As part of SDK setup you can customize the challenge user interface - [Android](https://cardinaldocs.atlassian.net/wiki/spaces/CMSDK/pages/1998914483/Challenge+User+InterfaceCustomization+Android-+V+2.2.5) - [iOS](https://cardinaldocs.atlassian.net/wiki/spaces/CMSDK/pages/2005696657/Challenge+User+Interface+Customization+iOS+V+2.2.5) ## 3DS1 Challenge display If the `authentication.version` is `1.x.x` use the following steps to display the challenge screen. Note 3DS version 1 was implemented by issuers long before smartphones existed so offers a degraded experience compared to version 2. We expect version 1 traffic from issuers to drop during 2021. #### Challenge form (webView) POST the request to the `challenge.url` with the `challenge.jwt` and optional `MD`. The `MD` field allows you to pass url parameters (max 1024 characters) in the challenge form that is included/echoed in the response url (`challenge.returnUrl`). details summary iOS Add a WKWebView to your Storyboard and UIViewController and enable JavaScript ``` @IBOutlet var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() webView.configuration.preferences.javaScriptEnabled = true } ``` Implement a method similar to the code snippet below in your UIViewController ``` let iframeSrcDoc = """
""" // A viewport meta tag is used to scale the content nicely to the device's screen size let html = """ """ webView.loadHTMLString(html, baseURL: URL(string: "about:srcdoc")!) ``` details summary Android Add a WebView to your fragment and enable JavaScript Kotlin ``` override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val webView = view.findViewById(...) webView.settings.javaScriptEnabled = true } ``` Java ``` @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); WebView webView = view.findViewById(...); webView.getSettings().setJavaScriptEnabled(true); } ``` Implement a method similar to the code snippet below in your Fragment Kotlin ``` val iframeSrcDoc = """
""" // A viewport meta tag is used to scale the content nicely to the device's screen size val html = """ """ webView.loadData(html, "text/html; charset=utf-8", "UTF-8") ``` Java ``` String challengeUrl = "add challengeUrl here"; String iframeSrcDoc = "" + "" + "
" + "" + "" + "
" + "" + ""; // A viewport meta tag is used to scale the content nicely to the device's screen size String html = "" + "" + "" + "" + "" + "" + ""; webView.loadData(html, "text/html; charset=utf-8", "UTF-8"); ``` #### Intercept challenge return Intercept the POST request to your `challenge.returnUrl` details summary iOS Have your UIViewController adopt the WKNavigationDelegate protocol Point the navigationDelegate property of your WKWebView to your UIViewController, just before the call to webView.loadHTMLString ``` webView.navigationDelegate = self ``` Implement the following method in your UIViewController to be notified when the challenge has been completed ``` func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) { if navigationAction.request.url!.absoluteString == "" { // TODO: add your logic } decisionHandler(.allow) } ``` details summary Android Intercept the POST request to your challenge return url Create a class that extends WebViewClient and override the onLoadResource method to be notified when the challenge has been completed Kotlin ``` private class CustomWebViewClient: WebViewClient() { override fun onLoadResource(view: WebView?, url: String?) { if (url.toString() == "") { // TODO: add your logic } super.onLoadResource(view, url) } } ``` Java ``` private static class CustomWebViewClient extends WebViewClient { @Override public void onLoadResource(WebView view, String url) { if (url.equals("")) { // TODO: add your logic } super.onLoadResource(view, url); } } ``` Set the webViewClient property of your WebView to an instance of this class, just before the call to webView.loadData() Kotlin ``` webView.webViewClient = CustomWebViewClient() ``` Java ``` webView.setWebViewClient(new CustomWebViewClient()); ``` # Verification Once the challenge has been completed, a verification request needs to be made to verify the result of the challenge. Important You should only request the verification from your backend system, not call it directly from the mobile application using the Access credentials. POST your verification request to our `3ds:verify` action link received in your authentication response. ## Verification example request Note You must use `v2` and later of the API for the Android/iOS SDK POST `https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/verification` Verification request body: { "transactionReference": "unique-transactionReference", "merchant": { "entity": "default" }, "challenge": { "reference": "123456789" } } ## Verification responses Here are examples of the verification responses you would receive. Authenticated { "outcome": "authenticated", "transactionReference": "unique-transactionReference", "authentication": { "version": "2.1.0", "authenticationValue": "MAAAAAAAAAAAAAAAAAAAAAAAAAA=", "eci": "05", "transactionId": "c5b808e7-1de1-4069" } } Authentication Failed { "outcome": "authenticationFailed", "transactionReference": "unique-transactionReference", "authentication": { "version": "1.0.2", "eci": "00", "transactionId": "N+en2I5+ZK/kQqk69wXdI8XIPg8=" }, "_links": { "3ds:authenticate": { "href": "https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/authentication" }, "curies": [{ "href": "https://try.access.worldpay-bsh.securedataplatform.com/rels/verifications/customers/3ds/{rel}", "templated": true, "name": "3ds" }] } } Signature Failed { "outcome": "signatureFailed", "transactionReference": "unique-transactionReference", "authentication": { "version": "1.0.2", "eci": "02" }, "_links": { "3ds:authenticate": { "href": "https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/authentication" }, "curies": [{ "href": "https://try.access.worldpay-bsh.securedataplatform.com/rels/verifications/customers/3ds/{rel}", "templated": true, "name": "3ds" }] } } Unavailable { "outcome": "unavailable", "transactionReference": "unique-transactionReference", "_links": { "3ds:authenticate": { "href": "https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/authentication" }, "3ds:verify": { "href": "https://try.access.worldpay-bsh.securedataplatform.com/verifications/customers/3ds/verification" }, "curies": [{ "href": "https://try.access.worldpay-bsh.securedataplatform.com/rels/verifications/customers/3ds/{rel}", "templated": true, "name": "3ds" }] } } Bypassed { "outcome": "bypassed", "transactionReference": "6032c024-8d33-4e89-98e9-a944f66c3906", "authentication": { "version": "2.1.0", "eci": "00", "transactionId": "c5b808e7-1de1-4069-a17b-f70d3b3b1645" } } Use the values: `version`, `authenticationValue`, `eci`, `transactionId` from the request when [authorizing a payment](/products/card-payments/v6/authorize-a-payment#authorize-a-payment). The values prove that the verification was successful, and that the fraud liability has shifted to the issuer. | Parameter | Description | | --- | --- | | `authentication.version` | The version of 3DS used to process the transaction. Required for Mastercard's Identity Check transactions in Authorization. | | `authentication.authenticationValue` | A cryptographic value that provides evidence of the outcome of a 3DS verification.Visa - Cardholder Authentication Verification Value (CAVV)Mastercard - Universal Cardholder Authentication Field (UCAF)Used when [authorizing a payment](/products/card-payments/v6/authorize-a-payment). | | `authentication.eci` | Electronic Commerce Indicator (ECI).Indicates the outcome of the 3DS authentication.02 or 05 - Fully Authenticated Transaction01 or 06 - Attempted Authentication Transaction00 or 07 - Non 3-D Secure TransactionMastercard - 02, 01, 00Visa - 05, 06, 07Amex - 05, 06, 07JCB - 05, 06, 07Diners - 05, 06, 07 You will need to use this when you are [authorizing a payment](/products/card-payments/v6/authorize-a-payment). | | `authentication.transactionId` | A transaction identifier.If provided, you should use it as part of your [payment authorization](/products/card-payments/v6/authorize-a-payment).If the `authentication.version` has a major version of:`1` - value returned known as `xid``2` - value returned known as `dsTransactionId` | **Next steps** [Take a payment](/products/card-payments/v6/authorize-a-payment#3ds)