Configure 3D Secure for your Primer account

Follow the below process to start using 3DS on sandbox immediately. Do note that for 3DS to work in production, you will need to complete the process described in step 4.

To get 3DS configured and running, you need to:

  1. 1
    Set up your workflow
  2. 2
    Configure your Client Session
  3. 3
    Handle 3DS in Universal Checkout
  4. 4
    Onboard your 3DS profile to go live

1. Set up your workflow

Configuring 3DS settings for your payments takes place within the "Authorize payment" Action. Learn more here about how to set up a workflow to process payments.

Example of setting up a workflow

In the configuration panel, you need to choose which 3DS option you want for all payments processed by this Action block:

🚫

No 3DS

3DS will not be used for any payments processed by this block. Payments will be declined when the Issuer requires authentication.

⭐️

Adaptive 3DS

Use Primer’s proprietary Adaptive 3DS which will only carry out 3DS authentication if the payment would be declined without it.

🔨

Primer 3DS

3DS authentication will be handled by Primer's agnostic 3DS solution for payments processed by this block. This could either be a challenge or frictionless.

💳

Processor 3DS

Your processor will present a 3DS challenge according to their configuration. This isn't compatible with Fallbacks as Primer is not involved in the flow.

2. Configure your Client Session

You need to pass the following field in POST/client-session:

FieldDescriptionRequired
  1. customer
  2. emailAddress
The customer's email addressYes

To improve 3DS success rates, it is recommended to pass the following field in POST/client-session:

FieldDescriptionRequired
  1. customer
The customer's billing addressRecommended

In Sandbox, both the email address and billing address must be provided to trigger 3DS.

3. Handle 3DS in Universal Checkout

Install 3DS SDK

3D Secure on React Native requires the addition of the 3DS SDK on iOS and Android.

On iOS

Adding 3D Secure to iOS via React Native requires the addition of the Primer3DS pod to your Podfile.

Depending on how you are using CocoaPods, you may need to add additional configuration to your Podfile. We support three methods for integration: static library, dynamic framework and static framework.

You can check which of the three your project is using by running bundle exec pod install in the ios folder of your project and checking the output.

e.g.

123
❯ bundle exec pod installFramework build type is static library...
shell
copy
Using static libraries

By default, react native apps link pods as static libraries. You can check if your app is using static libraries by running bundle exec pod install. If it is, you should see the following first line of output:

123
❯ bundle exec pod installFramework build type is static library....
shell
copy

To correctly link the 3DS pod as a static library, open Podfile inside the ios directory of your React Native project in a text editor, then add the following:

1234567891011121314151617181920212223242526272829303132333435
target 'MyApp' do
  # ... other CocoaPods config ...
  pod 'Primer3DS'
  post_install do |installer|
    # ... other post_install step config ...
    # Add this block, taking care to choose the correct config.build_settings['OTHER_SWIFT_FLAGS'] based on the directive below.    installer.pods_project.targets.each do |target|      if target.name == "primer-io-react-native" || target.name == "PrimerSDK"        target.build_configurations.each do |config|          config.build_settings['FRAMEWORK_SEARCH_PATHS'] = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS"          config.build_settings['LIBRARY_SEARCH_PATHS'] = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS"          config.build_settings['SWIFT_INCLUDE_PATHS'] = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS"
          # Note, depending on your integration type, you must choose one of the following settings:          # If you are using frameworks, add the following line          config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS/Primer3DS.modulemap"'
          # If you are using static libraries, instead add this line          config.build_settings['OTHER_SWIFT_FLAGS'] = '$(inherited) -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS/Primer3DS.framework/Modules/Primer3DS.modulemap"'
          config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -weak_library -l"Primer3DS"'        end      end    end
    # ... other post_install step config ...
  end
end
ruby
copy

Finally run bundle exec pod install to finish setting up.

Using dynamic frameworks

Although React Native uses static libraries by default, native iOS apps commonly use dynamic frameworks. You can check if your app is using dynamic frameworks by running bundle exec pod install. If it is, you should see the following first line of output:

123
❯ bundle exec pod installConfiguring Pod with dynamically linked Frameworks...
shell
copy

To correctly link the 3DS pod as a dynamic framework, simply add it to the Podfile inside the ios directory of your React Native project using a text editor:

1234567
target 'MyApp' do
  # ... other RN iOS config ...
  pod 'Primer3DS'
end
ruby
copy

Finally run bundle exec pod install to finish setting up.

As it is dynamically linked, it will automatically be detected by our iOS SDK at runtime, so no additional config is needed.

Using static frameworks

Static frameworks are a less common use case, but we are able to support it by configuring your Podfile to allow a mix of statically and dynamically linked frameworks, with the 3DS pod being linked dynamically.

You can check if your app is using static frameworks by running bundle exec pod install. If it is, you should see the following first line of output:

123
❯ bundle exec pod installConfiguring Pod with statically linked Frameworks...
shell
copy
⚠️

Note: it might be that your Podfile is overriding the use_frameworks directive elsewhere, in which case the above shell output may appear incorrect.

Check for the following in the app target of your Podfile:

1
use_frameworks! :linkage => :static
ruby
copy

If this is present, then you are using static frameworks by default, even if the shell output for bundle exec pod install says differently.

Because the 3DS pod is resolved by our SDK at runtime, an additional plugin is required to ensure that it can be loaded correctly.

Start by adding the following to the end of the Gemfile in the root of your app repo:

1
gem 'cocoapods-pod-linkage`
ruby
copy

Then, from the same folder (root of your app repo), run bundle install in a terminal:

1234567
❯ bundle installFetching gem metadata from https://rubygems.org/.......Resolving dependencies...Fetching cocoapods-pod-linkage 0.0.1Installing cocoapods-pod-linkage 0.0.1Bundle complete! 3 Gemfile dependencies, 40 gems now installed.Bundled gems are installed into `./vendor/bundle`
shell
copy

Add the plugin to your Podfile by including the line:

1
plugin 'cocoapods-pod-linkage'
ruby
copy

e.g.

12345678
linkage = ENV['USE_FRAMEWORKS']if linkage != nil  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green  use_frameworks! :linkage => linkage.to_symend
# 👇 Add this line here, below the framework linkage checkplugin 'cocoapods-pod-linkage'
ruby
copy

Then, add the SDK and 3DS pods to your app target in the Podfile:

12345678910111213
# ℹ️ This is already present if you are using static frameworks# If this is not present then the USE_FRAMEWORKS environmental variable will be set to `static`use_frameworks! :linkage => :static
target 'MyApp' do
  # ... other CocoaPods config ...
  # 👇 Add these lines to ensure both the SDK pod and 3DS pod are linked dynamically  pod 'PrimerSDK', :linkage => :dynamic  pod 'Primer3DS', :linkage => :dynamic
end
ruby
copy

Then, add the following to the post_install block:

12345678910111213141516171819202122232425
target 'MyApp' do
  # ... other CocoaPods config ...
  post_install do |installer|
    # ... other post_install step config ...
    # Add this entire block    installer.pods_project.targets.each do |target|      if target.name == "primer-io-react-native" || target.name == "PrimerSDK"        target.build_configurations.each do |config|          config.build_settings['FRAMEWORK_SEARCH_PATHS'] = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS"          config.build_settings['LIBRARY_SEARCH_PATHS'] = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS"          config.build_settings['SWIFT_INCLUDE_PATHS'] = "$(inherited) ${PODS_CONFIGURATION_BUILD_DIR}/Primer3DS"          config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -framework Primer3DS'        end      end    end
    # ... other post_install step config ...
  end
end
ruby
copy

Note: We recommend putting the above immediately after the call to react_native_post_install.

Finally, run bundle exec pod install to finish setting up.

On Android

3D Secure on Android requires the addition of the io.primer:3ds-android library to your project.

  1. 1

    Navigate to the ./android directory in your React Native project.

  2. 2

    Amend the dependencies section of your app's build.gradle to include the 3ds-android library. Paste this code, make sure to replace supported-3ds-sdk-version with the right value. See the table below to get the correct one:

    12345
    dependencies {  /* Other dependencies... */
      implementation "io.primer:3ds-android:{supported-3ds-sdk-version}"}
    bash
    copy

Interoperability matrix

Primer SDK internally uses Primer 3DS SDK as a compile time dependency. In order for the SDKs to work properly, the versions used internally and the one imported to your code must match.

Here is a breakdown of supported interoperable versions:

Android
Primer SDK versionPrimer 3DS SDK version
2.27.6+1.4.3
2.27.0 - 2.27.51.4.2
2.25.0 - 2.27.01.4.1
2.24.0 - 2.25.01.4.0
2.21.0 - 2.24.01.3.0
2.17.2 - 2.20.01.2.0
2.16.0 - 2.17.11.1.2
2.15.0 - 2.15.11.1.1
2.0.0 - 2.14.11.1.0
iOS
Primer SDK versionPrimer 3DS SDK version
>= 2.19.0>= 2.1.0
<= 2.18.32.0.0 - 2.0.2

Handle Out-of-Band (OOB) redirects (Optional)

Starting from 3D Secure protocol version 2.2.0, you can enhance the user experience by implementing an automatic redirect from another (authentication) application during an OOB challenge to your application once the challenge is successfully completed. This feature allows for a seamless transition and improved user flow.

⚠️

If this feature is not implemented, the user will have to come back to your application manually to complete their payment, which adds significant friction.

To enable this feature, ensure that you include the threeDsAppRequestorUrl parameter when configuring the threeDsOptions property of your settings for each platform.

Please note that the ios.threeDsAppRequestorUrl value must be an iOS Universal Link and the android.threeDsAppRequestorUrl value must be an Android App Link in order to facilitate the redirection.

To configure the Universal Link correctly using Universal Checkout, follow these steps:

    1234567891011121314
    const settings: PrimerSettings = {  // ...  paymentMethodOptions: {    threeDsOptions: {      iOS?: {        threeDsAppRequestorUrl?: string;      }      android?: {        threeDsAppRequestorUrl?: string;      }    },    // ...  }}
    tsx
    copy
    1. 3

      Follow Step 2 & 3 from the iOS guide.

    2. 4

      Follow Steps 1 to 3 from the Android guide.

    Execute 3D Secure

    Universal Checkout drop-in and headless automatically render the 3DS challenge when required by your workflow.

    If this application is not installed from a trusted source (e.g. a debug version, not installed from store, or used on an emulator), try to set PrimerDebugOptions.is3DSSanityCheckEnabled to false. Otherwise 3D Secure library initialization will fail due to security checks being performed.

    ⚠️

    is3DSSanityCheckEnabled flag should only be used in development mode, and not in production release of your app.

    123456
    const settings: PrimerSettings = {    // ...    debugOptions: {        is3DSSanityCheckEnabled: true,    },}
    tsx
    copy

    4. Onboard your 3DS profile to go live

    Before going live with 3DS on Primer, your account has to be configured with your 3DS profile(s). This 3DS profile consists of the following fields for each card network:

    • Acquirer Merchant ID (MID)
    • Acquirer BIN
    • Merchant Category Code (MCC)

    Please reach out to us directly via our Service Desk to configure this. If you don’t have access, please contact your account administrator for assistance.

    Test 3D Secure

    Monitor 3DS

    You can monitor 3DS on Primer in three main ways:

    • Payment status update webhook
    • Payments API
    • Payment timeline

    1. Payment status update webhook

    Subscribe to the payment status update webhook to receive notification updates each time your payment changes status.

    As part of the webhook body, the threeDSecureAuthentication object is included detailing the outcome. Below is an example of this object for a successful 3DS authentication:

    12345
    {    "responseCode": "AUTH_SUCCESS",    "protocolVersion": "2.2.0",    "challengeIssued": true}
    json
    copy

    2. Payments API

    Using Primer's Payments API, you can retrieve the payment object, where the threeDSecureAuthentication object is included detailing the outcome. This is available in the GET/payments/{paymentId} request, alongside POST/payments.

    Below is an example for an unsuccessful 3DS authentication:

    1234567
    {    "responseCode": "AUTH_FAILED",    "reasonCode": "CARD_AUTHENTICATION_FAILED",    "reasonText": "Card Authentication Failed",    "protocolVersion": "2.1.0",    "challengeIssued": true}
    json
    copy

    3. Payment timeline

    You can see all your Primer payments from the Payments timeline in the Primer Dashboard.

    Navigate to the specific payment detailed timeline page. You will see the 3DS authentication event. Select this event to open the side drawer that contains the data tied to this 3DS event.

    3DS Side Drawer Example