Keep your transactions compliant with Strong Customer Authentication (SCA) requirements and bring more friendly user experience to your customers with a 3D Secure 2, also known as EMV 3D Secure, a brand new secure authentication protocol which supports app-based authentication. Mobile SDK makes it easy to integrate all new 3DS features into your e-commerce app.
In the app-based flow, a cardholder initiates a transaction on a mobile device (Android or iOS) from a 3DS-enabled app. Mobile SDK collects and encrypts data from the mobile device, and sends it to the issuer bank. Based on the data, the bank decides whether additional cardholder interaction is required.
Frictionless flow
The authentication is achieved without cardholder interaction.
Challenge flow
Cardholder interaction is required to authenticate the payment. With Mobile SDK, the authentication is embedded natively in app, i.e no redirects to a browser. There are a variety of authentication options which the bank can initiate. It can be a simple password input in a native UI, an OTP, or an "out-of-band authentication", where the authentication happens via fingerprint or facial recognication in the banking app. Check Advanced Options for more details.
The Mobile SDK (MSDK) provides seamless integration with 3D Secure 2 payments.
Integration steps differs depending on how MSDK is used in your app. In these guides we assume that you already integrated base MSDK to make payments with one of the following ways:
Your Custom UI - using MSDK just for sending transactions.
Where do I start?
3D Secure 2 should work out of the box with the MSDK. Just configure 3DS 2 in the Administration Portal, import 3DS library to your project, and you are ready to run first 3DS 2 transaction.
Import the library
If you followed Install the SDK guide, then the library ipworks3ds_sdk is already installed. No extra imports is required.
There are two versions of the ipworks3ds_sdk: one to be used for development and one for production. The production version includes more strict security measures that would not allow for common development processes to occur, including running with attached debuggers or using simulators/emulators. In particular, the production version does not work with apps outside the official app/play store. The production version includes _deploy in the filename.
We assume that you already went through the base MSDK integration guide and can submit payments. If yes, proceed with the following instructions to enhance payments with the 3D Secure 2 verification.
NOTE: First of all, proper configuration in the Administration Portal should be done to enable 3DS 2 for the specific card brands.
There are no mandatory steps for 3D Secure 2 integration, everything is working out of the box. However, we strongly recommend to look through the Advanced Options. Use the threeDSConfig property of the OPPCheckoutSettings instance to apply customizations.
let config = OPPThreeDSConfig()
checkoutSettings.threeDSConfig = config
CheckoutSettings checkoutSettings = new CheckoutSettings(checkoutId, paymentBrands, providerMode);
ThreeDSConfig.Builder configBuilder = new ThreeDSConfig.Builder();
checkoutSettings.setThreeDS2Config(configBuilder.build());
val checkoutSettings = CheckoutSettings(checkoutId, paymentBrands, providerMode)
val configBuilder =ThreeDSConfig.Builder()
checkoutSettings.setThreeDS2Config(configBuilder.build())
We assume that you already went through base MSDK integration guide and can submit payments. If yes, proceed with the following instructions to enhance payments with the 3D Secure 2 verification.
NOTE: First of all, proper configuration in the Administration Portal should be done to enable 3DS 2 for the specific card brands.
Implement challenge callback
You need to implement the protocol OPPThreeDSEventListener:
onThreeDSChallengeRequiredWithCompletion method for displaying challenge screen; and
onThreeDSConfigRequiredWithCompletion method used for providing additional 3DS Service configurations.
You need to implement ThreeDSWorkflowListener:
onThreeDSChallengeRequired method for displaying challenge screen; and
onThreeDSConfigRequired method used for providing additional 3DS Service configuration.
Create listener:
ThreeDSWorkflowListener threeDSWorkflowListener = new ThreeDSWorkflowListener() {
@Override
public Activity onThreeDSChallengeRequired() {
// provide your Activity
return activity;
}
@Override
public ThreeDSConfig onThreeDSConfigRequired() {
// provide your ThreeDSConfig
return threeDSConfig;
}
};
val threeDSWorkflowListener: ThreeDSWorkflowListener = object : ThreeDSWorkflowListener {
override fun onThreeDSChallengeRequired(): Activity {
// provide your Activity
return activity
}
override fun onThreeDSConfigRequired(): ThreeDSConfig {
// provide your ThreeDSConfig
return threeDSConfig
}
}
From now just follow with Submit Transaction step of MSDK Custom UI integration guide. All 3D secure 2 actions are integrated within payment request.
Handling the app process destruction during the 3DS flow
If app goes to the background during the 3DS flow, it might be destroyed by OS because of low memory. In this case the transaction state will be lost. To handle this case the ThreeDS2Service provides static method wasTransactionKilled(), it can be called after app restart.
if (ThreeDS2Service.wasTransactionKilled()) {
// request payment status
}
if (ThreeDS2Service.wasTransactionKilled()) {
// request payment status
}
Device information is gathered by the Mobile SDK from a shopper device during 3DS Service initialization. By default, SDK collects as many parameters as it can. The full list of device info can be found in the EMVCo Specifications, check the file called "EMV® 3-D Secure SDK—Device Information".
App permissions
Some device data requires specific permissions to be granted, see the table below.
Data source
Permission type
Required permissions
Telephony Manager
Run-time permissions
This group of parameters requires the following permissions:
android.permission.SEND_SMS android.permission.READ_PHONE_STATE android.permission.READ_PHONE_NUMBERS
User approval is not required for API 22 and earlier because these permissions are granted during installation.
Wifi Manager
Installation-time permissions
android.permission.ACCESS_WIFI_STATE
Bluetooth Manager
Installation-time permissions
android.permission.BLUETOOTH
Device data blacklist
You can set a list of parameters which should not be pulled from the device because of some market or regional restrictions. Use identifiers from the "EMV® 3-D Secure SDK—Device Information" file, e.g. I001, I002A001, A002, and add this info to the 3DS config.
val configBuilder = ThreeDSConfig.Builder()
val blacklist = arrayOf("A001", "A002")
configBuilder.setDeviceParameterBlacklist(blacklist)
checkoutSettings.setThreeDS2Config(configBuilder.build())
Security
As soon as 3DS Service is initialized, you may want to verify security warnings and abort the transaction in case of high risk. Here is the list of possible security warnings to be detected:
paymentProvider!.securityWarnings { (warnings, error) in
if warnings.count > 0 {
// handle warnings
}
}
If you use our Ready-to-use UI the right place to check warnings is a callback which is called before submitting the transaction. For this purpose, you should implement OPPCheckoutProviderDelegate to listen checkout eventsthe broadcast receiver to listen the intents from CheckoutActivity. See details in the MSDK guide.
public class CheckoutBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (CheckoutActivity.ACTION_ON_BEFORE_SUBMIT.equals(action)) {
if (intent.hasExtra(CheckoutActivity.EXTRA_THREEDS_WARNINGS)) {
List<Warning> threeDS2Warnings = intent
.getParcelableArrayListExtra(CheckoutActivity.EXTRA_THREEDS_WARNINGS);
// handle warnings
}
}
}
}
class CheckoutBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, oldIntent: Intent?) {
val action = oldIntent?.action
if (CheckoutActivity.ACTION_ON_BEFORE_SUBMIT == action) {
if (intent.hasExtra(CheckoutActivity.EXTRA_THREEDS_WARNINGS)) {
val threeDS2Warnings: List<Warning> = intent
.getParcelableArrayListExtra(CheckoutActivity.EXTRA_THREEDS_WARNINGS)
// handle warnings
}
}
}
}
If you use Mobile SDK and Your Custom UI you can invoke this method anywhere in your code.
val threeDS2Warnings: List<Warning> = paymentProvider!!.threeDS2Warnings
App bundle identifier
The expected bundle identifier for the application. This should match the Bundle Identifier identity setting specified when building the application. A security warning (SW02) is raised if this value does not match the Bundle ID of the application at runtime.
Note that this value should not be hardcoded in the app for security reasons. You should store it on your server and retrieve it in runtime.
let config = OPPThreeDSConfig()
config.appBundleID = "com.companyname.appname"
checkoutSettings.threeDSConfig = config
App signature
App signature is used to verify that application wasn't tampered before installation. SDK expects the value as the SHA256 fingerprint of the certificate used to sign the app. A security warning (SW02) is raised if this value does not match the real app signature.
Note that app signature should not be hardcoded in the app for security reasons. You should store it on your server and retrieve it in runtime.
ThreeDSConfig.Builder configBuilder = new ThreeDSConfig.Builder();
configBuilder.setAppSignature("85:05:D8:B8:26:C6:AB:C6:AB:0B:49:08:F8:6E:5D:DF:CD:FF:16:69:DD:B2:93:3B:78:9D:64:6A:DE:FC:7A:9F");
checkoutSettings.setThreeDS2Config(configBuilder.build());
val configBuilder = ThreeDSConfig.Builder()
configBuilder.setAppSignature("85:05:D8:B8:26:C6:AB:C6:AB:0B:49:08:F8:6E:5D:DF:CD:FF:16:69:DD:B2:93:3B:78:9D:64:6A:DE:FC:7A:9F")
checkoutSettings.setThreeDS2Config(configBuilder.build())
Apps filter
3DS Service checks the list of installed apps on the shopper device. If it finds any suspicious applications or those that are not installed from the trusted app stores, a security warning (SW02) will be raised.
By default, trusted store is
Google Play store (com.android.vending)
and malicious apps are:
de.robv.android.xposed
de.robv.android.xposed.installer
com.saurik.substrate
You are welcome to complete these lists with your values using config properties:
ThreeDSConfig.Builder configBuilder = new ThreeDSConfig.Builder();
configBuilder.setTrustedAppStores(new String[]{"com.xiaomi.market"})
.setMaliciousApps(new String[]{"de.robv.android.xposed"});
checkoutSettings.setThreeDS2Config(configBuilder.build());
val configBuilder = ThreeDSConfig.Builder()
configBuilder.setTrustedAppStores(arrayOf("com.xiaomi.market"))
.setMaliciousApps(arrayOf("de.robv.android.xposed"))
checkoutSettings.setThreeDS2Config(configBuilder.build())
Out-of-Band (OOB) authentication
Starting from 3D Secure version 2.2.0 OOB authenticating application can use special URL to call your application after an OOB authentication occurs.
You can set the URL in threeDSRequestorAppURL in OPPThreeDSConfig class. This is your app's URL in {CUSTOM_SCHEME}://{CUSTOM_DOMAIN} format. In an OOB authentication, the authenticating application uses this URL to call your merchant application after an OOB authentication occurs.
let config = OPPThreeDSConfig()
config.threeDSRequestorAppURL = "{CUSTOM_SCHEME}://{CUSTOM_DOMAIN}"
checkoutSettings.threeDSConfig = config
We strongly suggest to use threeDSRequestorAppURL different from shopperResultURL in order to simplify integration.
After successful OOB authentication redirect from authenticating application to merchant application will happen automatically.
Out-of-Band (OOB) authentication
Starting from 3D Secure version 2.2.0 OOB authenticating application can use special threeDSRequestorAppURL to call your application after an OOB authentication occurs.
After successful OOB authentication redirect from authenticating application to merchant application will happen automatically.
This URL is not used by default, you can enable it in the ThreeDSConfig.
ThreeDSConfig threeDSConfig = new ThreeDSConfig.Builder()
.setThreeDSRequestorAppUrlUsed(true)
.build();
checkoutSettings.setThreeDS2Config(threeDSConfig);
val threeDSConfig: ThreeDSConfig = ThreeDSConfig.Builder()
.setThreeDSRequestorAppUrlUsed(true)
.build()
checkoutSettings.threeDS2Config = threeDSConfig
UI customization
Mobile SDK allows to customize challenge screens to match your app's look-and-feel. API provides the following classes to customize specific elements on the screen:
Class
Description
ToolbarCustomization
Background color of the toolbar + header label customization
LabelCustomization
Heading text customization
TextCustomization
Non-heading text cusomization
TextBoxCustomization
Corner radius of input fields + label customization
ButtonCustomization
Button background color, corner radius and font customization. Make sure you set appropriate style for each type of buttons:
CANCEL - Button placed in the right corner of Toolbar
SUBMIT - Main action on the screen
RESEND - Secondary action
CONTINUE - Main action in case of authentication in the external app
NEXT - Main action in case of authentication consists of several steps
See the sample code how UI customization can be applied in your app:
let config = OPPThreeDSConfig()
let uiCustomization = UiCustomization()
let customButton = uiCustomization.getButtonCustomization(buttonType: .SUBMIT)
customButton.setTextColor(color: UIColor.white)
customButton.setBackgroundColor(color: UIColor.red)
config.uiCustomization = uiCustomization
checkoutSettings.threeDSConfig = config
ThreeDSConfig.Builder configBuilder = new ThreeDSConfig.Builder();
UiCustomization uiCustomization = new UiCustomization();
ButtonCustomization customButton = new ButtonCustomization();
customButton.setTextColor("#FFFFFF"); // White
customButton.setBackgroundColor("#951728"); // Dark red
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.SUBMIT);
configBuilder.setUiCustomization(uiCustomization);
checkoutSettings.setThreeDS2Config(configBuilder.build());
val configBuilder = ThreeDSConfig.Builder()
val uiCustomization = UiCustomization()
val customButton = ButtonCustomization()
customButton.textColor = "#FFFFFF" // White
customButton.backgroundColor = "#951728" // Dark red
uiCustomization.setButtonCustomization(customButton, UiCustomization.ButtonType.SUBMIT)
configBuilder.setUiCustomization(uiCustomization)
checkoutSettings.setThreeDS2Config(configBuilder.build())
Cardholder Information
Cardholder information is 3D Secure response field provided by ACS/Issuer to cardholder during a Frictionless or Decoupled transaction. The Issuer can provide information to cardholder. If this value is present in transaction response, this information is required to be displayed by merchant app to cardholder.
3D Secure App flow
Cardholder information can be retrieved in OPPTransaction object in 3D Secure app flow. Please refer Mobile SDK First Integration for more details.
- (void)handleSubmittedTransaction:(nullable OPPTransaction *)transaction error:(nullable NSError *)error {
//get Cardholder information
if (transaction.threeDS2Info.cardHolderInfo && [transaction.threeDS2Info.cardHolderInfo length] > 0) {
//display cardholder info to user
}
}
func handleSubmittedTransaction(transaction: OPPTransaction?, error: Error?) {
//get Cardholder information
let cardholderInfo = transaction.threeDS2Info?.cardHolderInfo
if cardholderInfo != nil , !cardholderInfo!.isEmpty {
//display cardholder info to user
}
}
Cardholder information can be retrieved in Transaction object available in CheckoutActivityResult in 3D Secure app flow. Please refer Mobile SDK First Integration for more details.
private void handleCheckoutResult(@NonNull CheckoutActivityResult result) {
Transaction transaction = result.getTransaction();
String cardHolderInfo = null;
if (tranasction != null) {
//get Cardholder information
if (transaction.getThreeDS2Info() != null
&& (transaction.getThreeDS2Info().getCardHolderInfo() != null)) {
cardHolderInfo = transaction.getThreeDS2Info().getCardHolderInfo();
if (cardHolderInfo != null) {
//display cardholder info to user
}
}
}
}
private fun handleCheckoutActivityResult(result: CheckoutActivityResult) {
val transaction = result.transaction
val cardHolderInfo = transaction?.threeDS2Info?.cardHolderInfo
if (cardHolderInfo != null) {
//display cardholder info to user
}
}
3D Secure Web flow
Cardholder information can be retrieved in request payment status JSON response in 3D Secure web flow. Please refer Mobile SDK First Integration for more details.
static func cardHolderInfo(_ response: [String: Any]) -> String {
var cardholderInfoDesc = ""
if let resultDetails = response["resultDetails"] as? [String: Any] {
if let cardholderInfo = resultDetails["cardholderInfo"] as? String {
cardholderInfoDesc = cardholderInfo
}
}
return cardholderInfoDesc
}
Cardholder information can be retrieved in request payment status JSON response in 3D Secure web flow. Please refer Mobile SDK First Integration for more details.
@Nullable
public static String getCardHolderInfo(@NonNull String response)
throws Exception {
JSONObject responseJson = new JSONObject(response);
if (responseJson.has("resultDetails")) {
JSONObject resultDetails = responseJson.getJSONObject("resultDetails");
if (resultDetails.has("cardholderInfo")) {
return resultDetails.getString("cardholderInfo");
}
}
return null;
}
fun getCardHolderInfo(response:String) {
val responseJson = new JSONObject(response);
if (responseJson.has("resultDetails")) {
val resultDetails = responseJson.getJSONObject("resultDetails")
if (resultDetails.has("cardholderInfo")) {
return resultDetails.getString("cardholderInfo")
}
}
return null
}