For any question, we are one click away

Contact us

3DS2 SDK process

The diagram below shows the 3DS2 SDK payment process.

Be aware that many issuers' ACS don't work properly with 3DS Mobile SDKs.

sequenceDiagram participant MA as Mobile App participant MS as Mobile Server participant SDK2 as 3DS2 SDK participant PG as Payment Gateway participant 3DS as 3DSS/ACS/DS MA ->> MS: 1. client creates an order MS ->> PG: 2. register order via API PG -->> MS: 3. unique order number (mdOrder) MA ->> MA: 4. client enters data MA ->> MS: 5. send payment data to server MS ->> PG: 6. call payment API with threeDSSDK alt Payment finished PG -->> MS: 7. response with payment status (go to 22) else 3DS2 required PG -->> MS: 8. response with 3DS2 SDK keys MS ->> MA: 9. send keys to Mobile App MA ->> SDK2: 10. init 3DS2 SDK SDK2 -->> MA: 11. collect device data MA ->> MS: 12. send device data MS ->> PG: 13. second payment API call PG -->> MS: 14. acs signed content MS ->> MA: 15. send acs data MA ->> SDK2: 16. init Challenge flow SDK2 ->> ACS: 17. communicates via CReq/CRes ACS -->> PG: 18. confirms transaction with AReq SDK2 -->> MA: 19. 3DS procedure is over MS ->> PG: 20. finish 3DS2 payment PG ->> PG: 21. make payment end opt Callback is configured PG -->> MS: 22. callback notification end MS ->> PG: 23. check payment status MS ->> MA: 24. show payment result to Client
  1. Client creates an order.
  2. Mobile Server registers that order in Payment Gateway via register.do.
  3. Mobile Server receives a unique order number mdOrder in response.
  4. Client fills in payment data.
  5. Mobile App sends payment data to Mobile Server.
  6. Mobile Server uses that payment data to make a payment via paymentorder.do request.
    • Send threeDSSDK=true to indicate that 3DS2 SDK should be used.
  7. Mobile Server gets a response with no ACS keys. It means that payment is completed and we need to go to step 22.
  8. Mobile Server gets a response with ACS keys.
    • Response must contain threeDSServerTransId and threeDSSDKKey.
    • Response should not contain threeDSMethodURL which is used in case of browser based redirect to ACS.
  9. Mobile Server sends 3DS2 SDK data to Mobile App
  10. Mobile App initiates 3DS2 SDK via createTransaction method.
    • directoryServerID depends on Payment System (for tests A000000003 can be used).
    • messageVersion is 2.1.0 for now.
    • pemPublicKeyfor Android and for iOS is a pem certificate that is got in response in threeDSSDKKey on step 10.
    • dsRootfor Android and for iOS depends on Payment System. Download test key.
  11. 3DS2 SDK collects device data and encrypts it.
  12. Mobile App sends encrypted device data to Mobile Server.
  13. Mobile Server initiates second payment API call via paymentorder.do request.
    • sdkEncData- encrypted device data that is returned in createTransaction method in 3DS2 SDK
    • threeDSServerTransactionID is returned in response to first payment call on step 10 in threeDSServerTransId parameter
    • threeDSSDKReferenceNumber is returned in createTransaction method in 3DS2 SDK
    • sdkEphemPubKey is returned in createTransaction method in 3DS2 SDK
    • sdkAppID is returned in createTransaction method in 3DS2 SDK
    • sdkTransID is returned in createTransaction method in 3DS2 SDK
  14. Payment Gateway returns new special parameters for 3DS2 SDK.
  15. Mobile Server sends those parameters to Mobile App.
  16. Mobile App initiates challenge flow via doChallenge method.
    • doChallenge acsTransactionIDparameter corresponds to threeDSAcsTransactionId in Payment Gateway response
    • doChallenge acsRefNumberparameter corresponds to threeDSAcsRefNumber in Payment Gateway response
    • doChallenge acsSignedContentparameter corresponds to threeDSAcsSignedContent in Payment Gateway response
    • doChallenge 3DSServerTransactionIDparameter corresponds to threeDSServerTransId in Payment Gateway response
  17. 3DS2 SDK communicates with issuers ACS via CReq/CRes API until Client confirms the payment.
  18. ACS sends RReq to Payment Gateway to confirm or reject the payment.
  19. 3DS2 SDK informs Mobile App that 3DS2 flow is over via ChallengeStatusReceiver.
  20. Mobile Server finalizes the payment with finish3dsVer2Payment.do.
  21. Payment Gateway makes a payment.
  22. Payment Gateway sends callback notification to Merchant server if it's configured for the merchant.
  23. Mobile Server checks the final payment status via getOrderStatusExtended.do.
  24. Mobile App shows payment result to the client.

IOS

iOS Integration

For integration SDK ThreeDS:

Image 1. Adding the ThreeDSSDK.framework file


Image 2. Adding the ThreeDSSDK.framework file


iOS Configuration

Example ThreeDSSDK

Full example can be found here: TransactionManager

import UIKit
import ThreeDSSDK

....

var _service: ThreeDS2Service = Ecom3DS2Service()

// Init ThreeDS SDK
try _service.initialize(configParameters: ConfigParameters(), locale: Locale.current.languageCode, uiCustomization: _setUpTheme())
var _sdkTransaction = try _service.createTransaction(directoryServerID: "", messageVersion: nil, publicKeyBase64: "", rootCertificateBase64: "", logoBase64: "")

// get progress view
var _sdkProgressDialog = try _sdkTransaction!.getProgressView()

// Show progress dialog
_sdkProgressDialog?.show()

// get authentication request parameters, to be sent to the payment gateway
var authParameters = _sdkTransaction!.getAuthenticationRequestParameters()
var deviceData = authParameters.getDeviceData()
var ephemeralPublickKey = authParameters.getSDKEphemeralPublicKey()
var threeDSSDKAppId = authParameters.getSDKAppID()
var threeDSSDKTransId = authParameters.getSDKTransactionID()

// if you get error during initial sdk, you can close spinner.
// _sdkProgressDialog?.close()

// Set challenge parameters and start challenge flow
let challengeParameters = ChallengeParameters()
challengeParameters.setAcsSignedContent("acsSignedContent")
challengeParameters.setAcsRefNumber("acsReferenceNumber")
challengeParameters.setAcsTransactionID("acsTransID")
challengeParameters.set3DSServerTransactionID("threeDSServerTransID")
// Start challenge flow
self._sdkTransaction?.doChallenge(challengeParameters: challengeParameters, challengeStatusReceiver: self, timeOut: 5)

// If you get error during sdk flow, you can finish sdk transaction
// _sdkTransaction?.close()

// Delegate functions
extension TransactionManager: ChallengeStatusReceiver {
  public func completed(completionEvent e: CompletionEvent) {}
  public func cancelled() {}
  public func timedout() {}
  public func protocolError(protocolErrorEvent e: ProtocolErrorEvent) {}
  public func runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {}
}

Logging

Internal processes are logged with the SDK-ThreeDS tag. You can also log your processes. Logging is available through the ThreeDSLogger class which has an instance available through the static shared field. - To add log-interfaces you should call the ThreeDSLogger-method addLogInterface().

Example:

...
      final class Logger: LogProtocol {

          func log<T>(classMethod: T.Type, tag: String, message: String, exception: (any Error)?) {
              print("\(classMethod), \(tag), \(message), \(exception)")
          }
      }

      ThreeDSLogger.shared.addLogInterface(logger: Logger())
...

The default tag is SDK-ThreeDS. You can set your own one if you like.

Example:

...
     ThreeDSLogger.shared.log(classMethod: type(of: self), tag: "My tag", message: "My message", exception: nil)
...

Example:

...

   ThreeDSLogger.shared.setupLogUploaderConfigProvider(configProvider: ViewController())

...
   extension ViewController: LogUploaderConfigProvider {

      func provideConfig(sdkAppId: String?) -> ThreeDSSDK.LogUploaderConfig? {
        // use the sdkAppId to enable/disable logs or not   
        // enable logs upload
        return .sentry(url: "SentryURL", key: "SentryKey")

        // disable logs upload
        return nil
      }
}
...

Android

Android integration

Connecting the 3DS2 library

You need to add the sdk_threeds-release.aar library file to the libs folder, then specify the dependency on the added library.

In SDK versions <= 2.5.5 add the sdk_listeners_android.jar file to the libs folder. Since SDK 2.5.6 there is no need to add the sdk_listeners_android.jar file.

build.gradle.kts

allprojects {
    repositories {
       // ...
       flatDir {
          dirs("libs")
       }
    }
}

dependencies {
   // dependency for connecting the confirmation functionality via 3DS
   implementation(group = "", name = "sdk_threeds-release", ext = "aar")
   implementation("com.google.code.gson:gson:2.8.5")
   implementation("com.squareup.okhttp3:okhttp:3.11.0")
   implementation("com.google.android.gms:play-services-ads:17.2.1")
   implementation("com.google.android.gms:play-services-location:16.0.0")
}

build.gradle

allprojects {
    repositories {
       // ...
       flatDir {
          dirs 'libs'
       }
    }
}

dependencies {
   // dependency for connecting the confirmation functionality via 3DS
   implementation(group = "", name = "sdk_threeds-release", ext = "aar")
   implementation("com.google.code.gson:gson:2.8.5")
   implementation("com.squareup.okhttp3:okhttp:3.11.0")
   implementation("com.google.android.gms:play-services-ads:17.2.1")
   implementation("com.google.android.gms:play-services-location:16.0.0")
}

Android Configuration

Payment execution with confirmation via 3DS2

private val factory = Factory()

threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val uiCustomization = factory.newUiCustomization()
threeDS2Service.initialize(
    context,
    configParams,
    "en-US",
    uiCustomization,
    sslContext, // Optional field (needs if you want to pass a custom SSL certificate)
    trustManager, // Optional field (needs if you want to pass a custom SSL certificate)
)

// An example of creating a transaction with custom SSL certificate.
// To create a transaction with a custom certificate, you need to create an SSLContext object and a TrustManager. 
// Then pass it to initialize method of threeDS2Service.
// Both (sslContext and trustManager) parameters must be passed, or neither (they are optional).
//
// threeDS2Service.initialize(
//    context,
//    configParams,
//    "en-US",
//    uiCustomization,
//    sslContext, // Optional field
//    trustManager, // Optional field
// )

val dsRoot: String = "MII346GU349HDE5FH..." //your root-certificate in base64 format
val transaction = threeDS2Service.createTransaction("F000000000", "", "2.1.0", dsRoot)

//  An example of creating a transaction with deviceInfo encryption with a transmitted RSA key.
//  val rsaPem: String = ...
//  val dsRoot: String = ...
//  transaction = threeDS2Service.createTransaction(
//      "",
//      rsaPem,
//      "2.2.0",
//      dsRoot
//   )

//  An example of creating a transaction with deviceInfo encryption with a transmitted EC key.
//  val ecPem: String = ...
//  val directoryServerID: String = ...
//  val dsRoot: String = ...
//  transaction = threeDS2Service.createTransaction(
//      directoryServerID,
//      ecPem,
//      "2.2.0",
//      dsRoot
//   )

// Available data, to be sent to the payment gateway
val authRequestParams = transaction.authenticationRequestParameters!!
val encryptedDeviceInfo: String = authRequestParams.deviceData
val sdkTransactionID: String = authRequestParams.sdkTransactionID
val sdkAppId: String = authRequestParams.sdkAppID
val sdkEphmeralPublicKey: String = authRequestParams.sdkEphemeralPublicKey
val sdkReferenceNumber: String = authRequestParams.sdkReferenceNumber

val challengeParameters = factory.newChallengeParameters()

// Parameters for starting Challenge Flow.
challengeParameters.acsTransactionID =
    paymentOrderSecondStepResponse.threeDSAcsTransactionId
challengeParameters.acsRefNumber = paymentOrderSecondStepResponse.threeDSAcsRefNumber
challengeParameters.acsSignedContent =
    paymentOrderSecondStepResponse.threeDSAcsSignedContent
challengeParameters.set3DSServerTransactionID(paymentOrderResponse.threeDSServerTransId)

// Listener to handle the Challenge Flow execution process.
val challengeStatusReceiver: ChallengeStatusReceiver = object : ChallengeStatusReceiver {

    override fun cancelled() {}

    override fun protocolError(protocolErrorEvent: ProtocolErrorEvent) {}

    override fun runtimeError(runtimeErrorEvent: RuntimeErrorEvent) {}

    override fun completed(completionEvent: CompletionEvent) {}

    override fun timedout() {}
}

val timeOut = 5

// Starting Challenge Flow.
transaction.doChallenge(
    activity,
    challengeParameters,
    challengeStatusReceiver,
    timeOut
)

You can see a complete code sample in the file net.payrdr.mobile.payment.sample.kotlin.threeds.ThreeDSActivity.

Features of app self-test with connected 3DS2

When initializing the ThreeDS2Service, the application performs a series of self-compromising checks. The list with warnings is returned using the ThreeDS2Service.getWarnings method. If there are no warnings, an empty list is returned.

The list of checks includes:

  1. Checking root access on the device (according to SW01 rule )
    • It returns a warning when triggered The device is rooted.
  2. Checking to install the app only from approved app stores (according to SW02 rule)
    • It returns a warning when triggered The integrity of the SDK has been tampered.
    • By default, sdk allows installation of the application only from the Play Market.
    • If it is necessary to add other markets (for example, App Gallery), they can be passed to configParams.
val factory = Factory()
val threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val trustedAppStores = listOf<String>("com.android.vending", "com.huawei.appmarket")

configParams.removeParam("security", "trustedAppStores")
configParams.addParam("security", "trustedAppStores", StringUtils.makeString(trustedAppStores))
  1. Checking application signature mismatch (according to SW02 rule)
    • It returns a warning when triggered The integrity of the SDK has been tampered.
    • An example of passing a signature in configParams:
val factory = Factory()
val threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val youAppSignature = //signature of your application

    configParams.removeParam("security", "appSignature")
configParams.addParam("security", "appSignature", youAppSignature)
  1. Checking for malicious applications on the device (according to SW02 rule)
    • It returns a warning when triggered The integrity of the SDK has been tampered.
    • By default, applications with the following package names are denied:
      • de.robv.android.xposed
      • de.robv.android.xposed.installer
      • com.saurik.substrate
    • If it is necessary to set your own list of prohibited applications, the names of their packages can be passed to configParams.
val factory = Factory()
val threeDS2Service = factory.newThreeDS2Service()
val configParams = factory.newConfigParameters()
val maliciousApps = listOf<String>("com.zhiliaoapp.musically", "com.othersapp.harmful")

configParams.removeParam("security", "maliciousApps")
configParameters.addParam("security", "maliciousApps", StringUtils.makeString(maliciousApps))
  1. Checking to run the application from under the emulator (according to SW03 rule)
    • It returns a warning when triggered An emulator is being used to run the App.
  2. Checking for the presence of a debugger connected to the application (according to SW04 rule)
    • It returns a warning when triggered A debugger is attached to the App.
  3. Checking that the Android version is up-to-date (according to SW05 rule)
    • It returns a warning when triggered The OS or the OS version is not supported.
    • Versions over API 16 (JELLY BEAN) are considered to be up-to-date (safe)

Under documentation/threeds, you can find more information describing the available ConfigParameters and UiCustomization parameters to customize the 3DS screen, as well as the description of the 3DS SDK server application interaction process.

Example of a confirmation code input screen:

drawing

Logging

Internal processes are logged with the SDK-ThreeDS tag. You can also log your processes. Logging is available through the ThreeDSLogger class which has an instance available through the static INSTANCE field . - To add log- interfaces you should call the ThreeDSLogger-method addLogInterface().

Example for logging into LogCat:

...
     ThreeDSLogger.INSTANCE.addLogInterface(object : net.payrdr.mobile.payment.sdk.threeds.LogInterface {
        override fun log(classMethod: Class<*>, tag: String, message: String, p3: Throwable?) {
            Log.i(tag, "$classMethod: $message")
        }
    })
...

The default tag is SDK-ThreeDS. You can set your own one if you like.

...
     ThreeDSLogger.INSTANCE.log(this.javaClass, "MyTag", "My process", null)
...

Example:

...
    ThreeDSLogger.INSTANCE.setupLogUploaderConfigProvider { sdkAppId ->
        // use the sdkAppId to enable/disable logs or not   
        // enable logs upload
        SentryLogUploaderConfig.Builder()
            .withUrl("SentryURL")
            .withKey("SentryKey")
            .build()
        // disable logs upload
        null
}
...

3DS2 stub

3DS2 stub can be used with the SDK. SDK screens depend on the order amount in 3DS2 stub.

Radio group

Amount: 111

Multiple choice

Amount: 222

Web (embedded HTML)

Amount: 333

One-Time password

Amount: any other

Categories:
eCommerce SDK
Categories
Search results