3DS React Native SDK Enterprise
The Basis Theory react-native-threeds package makes it easy to start a 3DS transaction from a React Native mobile app. It offers two integrations: a WebView integration that runs the 3DS challenge in a WebView, and a native integration that runs the Basis Theory 3DS Mobile SDK for iOS and Android underneath.
Get started with our guide or continue reading the reference docs.
Before You Begin
This SDK requires the use of an API Key associated with a Public Application.
To create one, login into our Portal and create a new "Public" Application with the 3ds:session:create permission.
Installation
- npm
- yarn
npm install --save @basis-theory/react-native-threeds
yarn add @basis-theory/react-native-threeds
Choose an Integration
Both integrations follow the same flow: your app tokenizes the card, the SDK creates a 3DS session, and your backend authenticates the session with a private API key. The difference is who runs the challenge.
| Integration | iOS | Android | Expo Go | Challenge UI |
|---|---|---|---|---|
| WebView | Yes | Yes | Yes | A WebView rendered by BasisTheory3dsProvider over your app |
| Native | Yes | Yes | No | The bank's native challenge screen, presented by the platform SDK |
The native integration runs custom native code, so it needs a development build (expo prebuild) or a bare React Native app. Expo Go can only use the WebView integration.
With the WebView integration, your JavaScript calls your backend and decides whether to start the challenge. With the native integration, the platform SDK calls your authentication endpoint, presents the challenge when the bank requires one, and returns the result. Continue with Initialization for the WebView integration or Native 3DS for the native integration.
Initialization
BasisTheory3dsProvider
This Context Provider is used to wrap your application and provide the SDK instance to all the components in the tree.
Your app must have the BasisTheory3dsProvider at the root level to ensure the SDK hook methods are available to all components. The provider also renders the challenge WebView as an overlay on top of its children.
import { BasisTheory3dsProvider } from "@basis-theory/react-native-threeds";
const App = () => {
return (
<BasisTheory3dsProvider apiKey={"<API_KEY>"}>
<MyApp />
</BasisTheory3dsProvider>
);
}
Initialization Parameters
| Parameter | Required | Type | Description |
|---|---|---|---|
apiKey | true | string | The API Key used to identify the Application |
apiBaseUrl | false | string | The base URL for the Basis Theory API, if using a mock API. Takes precedence over region |
region | false | string | Selects the regional Basis Theory API host: us or eu |
scriptSrc | false | string | The source URL for the Basis Theory 3DS SDK CDN script |
useBasisTheory3ds
The useBasisTheory3ds hook provides access to the SDK methods. It must be used within a component that is a descendant of the BasisTheory3dsProvider.
import { BasisTheory3dsProvider, useBasisTheory3ds } from "@basis-theory/react-native-threeds";
const App = () => {
return (
<BasisTheory3dsProvider apiKey={"<API_KEY>"}>
<MyApp />
</BasisTheory3dsProvider>
);
}
const MyApp = () => {
const { createSession, startChallenge } = useBasisTheory3ds();
//... rest of your component
}
Native 3DS
@basis-theory/react-native-threeds 1.3.0 or later and React Native 0.81 or later. Apps on older React Native versions can keep using the WebView integration.The native integration is off by default, so apps that only use the WebView integration build exactly as before. Enabling it adds the platform 3DS SDKs and their requirements to your app's native build.
The native SDKs call your authentication endpoint with the session ID in the request body and expect a specific response, so check the Authentication Endpoint contract before you build it.
Native 3DS always uses https://api.basistheory.com. The native iOS and Android SDKs don't support regional API hosts yet.
Enable Native 3DS
Add this to your app's package.json, then rebuild the app:
{
"@basis-theory/react-native-threeds": {
"native": true
}
}
The package reads this setting during autolinking, so it applies to both Expo and React Native CLI projects. Only enable it if you use BasisTheoryThreeDS or BasisTheoryThreeDSStrategies.
Platform Requirements
- iOS
- Android
Run pod install after enabling native 3DS. The package's pod downloads Ravelin's 3DS SDK, which the 3DS Mobile SDK uses, from Ravelin's official release. The native integration requires iOS 15 or later.
Ravelin's 3DS SDK, which the 3DS Mobile SDK uses, needs two changes in your app module that a library can't make for you: core library desugaring, and excluding a META-INF file that both Ravelin's okhttp dependency and AndroidX ship, which would otherwise fail packaging. Add them based on how your project manages the android/ folder.
If you use expo prebuild, add the package's config plugin to app.json. It adds both to the generated android/app/build.gradle on every prebuild, so don't add them by hand:
{
"expo": {
"plugins": ["@basis-theory/react-native-threeds"]
}
}
If you use a bare React Native app, or an Expo app with a committed android/ folder, add these lines to android/app/build.gradle:
android {
compileOptions {
coreLibraryDesugaringEnabled true
}
packagingOptions {
resources {
excludes += "META-INF/versions/9/OSGI-INF/MANIFEST.MF"
}
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
}
The package adds Ravelin's Maven repository to your Gradle build automatically. If your settings.gradle sets repositoriesMode to PREFER_SETTINGS or FAIL_ON_PROJECT_REPOS, Gradle ignores or rejects that repository, so add https://maven.ravelin.com/public/repositories/threeds2service/ to dependencyResolutionManagement.repositories in settings.gradle instead.
Choose a Native Strategy
The native integration has two React Native strategies, the Bridge and the TurboModule, which expose the same methods. The Bridge is always available, and iOS builds with the new architecture add the TurboModule:
| Platform | Bridge | TurboModule |
|---|---|---|
| iOS | Always | Always on React Native 0.82 and later. On 0.81, when newArchEnabled is true: in app.json for Expo, or in ios/Podfile.properties.json for bare apps. Run pod install again after changing it |
| Android | Always | Not supported |
Use BasisTheoryThreeDS, which picks the TurboModule on iOS when your build includes it and the Bridge everywhere else. To force one strategy, use BasisTheoryThreeDSStrategies.ios.bridge, BasisTheoryThreeDSStrategies.ios.turboModule, or BasisTheoryThreeDSStrategies.android.bridge. ios.turboModule needs the new architecture, which you can check with isThreeDSTurboModuleAvailable().
import { Platform } from "react-native";
import {
BasisTheoryThreeDSStrategies,
isNativeThreeDSAvailable,
isThreeDSTurboModuleAvailable,
} from "@basis-theory/react-native-threeds";
// Force the TurboModule on iOS and the Bridge on Android.
const threeDS =
Platform.OS === "ios"
? BasisTheoryThreeDSStrategies.ios.turboModule
: BasisTheoryThreeDSStrategies.android.bridge;
const isAvailable =
Platform.OS === "ios" ? isThreeDSTurboModuleAvailable() : isNativeThreeDSAvailable;
const pay = async (tokenId) => {
if (!isAvailable) {
// This build doesn't include the strategy. Enable newArchEnabled and rebuild, or use BasisTheoryThreeDS.
return;
}
await threeDS.configure({
apiKey: "<PUBLIC_API_KEY>",
authenticationEndpoint: "https://your-backend.example.com/3ds/authenticate",
});
const session = await threeDS.createSession({ tokenId });
const result = await threeDS.startAuthentication(session.id);
};