Skip to content

Commit 38f4cb0

Browse files
MOB-743 #comment updated documentation
1 parent e3abfd7 commit 38f4cb0

File tree

10 files changed

+250
-66
lines changed

10 files changed

+250
-66
lines changed

README.md

Lines changed: 132 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,143 @@
1-
# react-native-ts-authentication
1+
# React Native - Transmit Security Authentication SDK
22

3-
React Native module for Transmit Security Authentication SDK
3+
Add strong authentication with Passkeys to your native iOS and Android applications, while providing a native experience. This describes how to use the React Native module to register credentials and use them to authenticate your users.
4+
5+
## About Authentication SDK
6+
7+
This SDK provides a unified solution for implementing both Apple's public-private key authentication for passkeys on iOS and Google's Credential Manager API for passkeys on Android. It enables the integration of FIDO2-based biometric authentication seamlessly into your mobile applications, offering users a native experience instead of a browser-based one. With passkeys, credentials are securely stored by the device, leveraging iCloud Keychain on iOS and Google Password Manager on Android. These credentials are associated with your domain, facilitating secure sharing between your mobile app and website if applicable.
8+
9+
Using this module, you can easily integrate our Authentication SDK into your React Native app for seamless and secure user identity authentication.<br>
10+
[Learn more about how you can boost your security with Transmit Security Authentication.](https://transmitsecurity.com/platform/full-stack-authentication)
11+
12+
## Understand the flow
13+
We recommended that you read more about the verification flow required steps in our [iOS documentation](https://developer.transmitsecurity.com/guides/webauthn/quick_start_sdk_ios/) and [Android documentation](https://developer.transmitsecurity.com/guides/webauthn/quick_start_sdk_android/#Command-line)
14+
15+
## Configure your app
16+
To integrate this module, you'll need to configure an application.
17+
18+
1. From the [Applications](https://portal.transmitsecurity.io/applications) page, [create a new application](https://developer.transmitsecurity.com/guides/user/create_new_application/) or use an existing one.
19+
2. From the application settings:
20+
* For Client type , select native
21+
* For Redirect URI , enter your website URL. This is a mandatory field, but it isn't used for this flow.
22+
* Obtain your client ID and secret for API calls, which are autogenerated upon app creation.
23+
* Enable public sign-up if you manage users using an external system (e.g., external identity provider) or if you want to quickly test WebAuthn registration and authentication without first logging in using a different authentication method.
24+
3. Refer to our iOS and Android documentation mentioned above to configure an auth method and associate your domain for Apple and Google.
25+
26+
## Example project setup
27+
#### Note: Configuring Google's assetlinks.json and Apple's apple-app-site-association according to the guidelines in our native SDKs documentation and the user-guides provided by Apple and Google can be a challenging task. However, it is crucial to complete this step accurately for both utilizing the example app and configuring your own application. Instead of attempting to configure this example directly, you are welcome to use it just as a code-reference to ensure proper implementation.
28+
29+
1. In your project, navigate to `example/src/config.ts` and configure the clientId, domain, secret and baseUrl using the configuration obtained from the Transmit portal.
30+
2. Ensure you have all the necessary dependencies by running `yarn` in both the module's root folder and the example root folder.
31+
3. Run the example app on a real device using Xcode or Android Studio. Alternatively, execute `yarn example ios` or `yarn example android`.
32+
<br><br>
33+
> **Important Security Note: Never store your `secret` in a front-end application.**
34+
>
35+
> The example app utilizes a mock server to manage communication with the authentication platform. This mock server employs the `secret` you have specified in `example/src/config.ts` exclusively for demonstration purposes. It is paramount that you safeguard your `secret` in a secure and confidential location.
436
537
## Installation
638

739
```sh
840
npm install react-native-ts-authentication
941
```
10-
ios setup
1142

12-
platform :ios, 15.0
43+
#### iOS Setup
44+
You might need to execute `pod install` in your project's `/ios` folder and set your minimum iOS target to 15.0 in your Podfile (e.g `platform :ios, 15.0`).
45+
46+
* Add project Capabilities as described [iOS quick start](https://developer.transmitsecurity.com/guides/webauthn/quick_start_sdk_ios/)
47+
* Update YOUR Bundle ID and setup associated domains as described in the [iOS quick start](https://developer.transmitsecurity.com/guides/webauthn/quick_start_sdk_ios/)
48+
49+
#### Android Setup
50+
51+
Add to `app/build.gradle` under repositories
52+
53+
```gradle
54+
repositories {
55+
google()
56+
maven {
57+
url('https://transmit.jfrog.io/artifactory/transmit-security-gradle-release-local/')
58+
}
59+
}
60+
```
61+
Note:
62+
As for projects on Gradle 8+ and Kotlin 1.8+ build will fail if the JDK version between
63+
compileKotlin and compileJava and jvmTarget are not aligned.
64+
65+
This won't be necessary anymore from React Native 0.73. More on this:
66+
https://kotlinlang.org/docs/whatsnew18.html#obligatory-check-for-jvm-targets-of-related-kotlin-and-java-compile-tasks
67+
68+
## Usage
69+
70+
#### Module Setup
71+
```js
72+
import TSAuthenticationSDKModule from 'react-native-ts-authentication';
73+
74+
componentDidMount(): void {
75+
// Setup the module as soon your component is ready
76+
this.onAppReady().catch(e => void e);
77+
}
78+
79+
private onAppReady = async (): Promise<void> => {
80+
/* Initialize the module with parameters:
81+
1. ClientID obtained from the application settings in the Transmit portal
82+
2. BaseURL can be "https://api.transmitsecurity.io" | eu = "api.eu.transmitsecurity.io" | ca = "api.ca.transmitsecurity.io"
83+
84+
*/
85+
const baseURL = "https://api.transmitsecurity.io";
86+
87+
TSAuthenticationSDKModule.initialize(
88+
"YOUR_CLIENT_ID",
89+
"YOUR_DOMAIN",
90+
`${baseURL}/cis/v1`
91+
);
92+
}
93+
```
94+
95+
#### First time authentication (Register a user)
96+
```js
97+
onStartRegistrationProcess = async (): Promise<void> => {
98+
try {
99+
const response = await TSAuthenticationSDKModule.register(username, displayName);
100+
// use the response.result string to complete a successful registration in your backend.
101+
} catch (error) {
102+
console.error(`Error authentication the user: ${error}`);
103+
}
104+
}
105+
```
106+
107+
#### Start the authentication process
108+
```js
109+
onStartAuthenticationProcess = async (): Promise<void> => {
110+
try {
111+
const response = await TSAuthenticationSDKModule.authenticate(username);
112+
// use the response.result string to complete a successful authentication in your backend.
113+
} catch (error) {
114+
console.error(`Error authentication the user: ${error}`);
115+
}
116+
}
117+
```
118+
119+
#### Sign a transaction
120+
```js
121+
onStartSignTransactionProcess = async (): Promise<void> => {
122+
try {
123+
const response = await TSAuthenticationSDKModule.signTransaction(username);
124+
// use the response.result string to complete a signing a transaction in your backend.
125+
} catch (error) {
126+
console.error(`Error authentication the user: ${error}`);
127+
}
128+
}
129+
```
130+
131+
## Important Notes
132+
1. Please take note that the example application uses a client-side mock server. In a production environment, a real server is required. Additionally, it is crucial to emphasize that storing the client secret in your front-end application is strictly discouraged for security reasons.
133+
134+
## Support
135+
[Email us for support](info@transmitsecurity.com)
136+
137+
## Author
13138

14-
add the capabilities
15-
https://developer.transmitsecurity.com/guides/webauthn/quick_start_sdk_ios/
139+
Transmit Security, https://github.com/TransmitSecurity
16140

141+
## License
17142

18-
update bundle id and setup associated domains iOS format example: webcredentials:shopcart.userid-stg.io (instruct to follow the tutorial for each platform)
143+
This project is licensed under the MIT license. See the LICENSE file for more info.

android/src/main/java/com/tsauthentication/TsAuthenticationModule.java

Lines changed: 96 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.facebook.react.bridge.ReactApplicationContext;
99
import com.facebook.react.bridge.ReactContextBaseJavaModule;
1010
import com.facebook.react.bridge.ReactMethod;
11+
import com.facebook.react.bridge.UiThreadUtil;
1112
import com.facebook.react.bridge.WritableMap;
1213
import com.facebook.react.bridge.WritableNativeMap;
1314
import com.facebook.react.module.annotations.ReactModule;
@@ -35,11 +36,17 @@ public String getName() {
3536

3637
@ReactMethod
3738
@NonNull public void initialize(String clientId, String domain, String baseUrl, Promise promise) {
38-
TSAuthentication.init(getReactApplicationContext(),
39-
baseUrl,
40-
clientId
41-
);
42-
promise.resolve(true);
39+
UiThreadUtil.runOnUiThread(
40+
new Runnable() {
41+
@Override
42+
public void run() {
43+
TSAuthentication.init(getReactApplicationContext(),
44+
baseUrl,
45+
clientId
46+
);
47+
promise.resolve(true);
48+
}
49+
});
4350
}
4451

4552
// Registration
@@ -49,62 +56,108 @@ public String getName() {
4956
String username,
5057
String displayName,
5158
Promise promise) {
52-
TSAuthentication.isPlatformAuthenticatorSupported(
53-
getReactApplicationContext(),
54-
new TSAuthCallback<Boolean>() {
55-
@Override
56-
public void success(Boolean aBoolean) {
57-
continueRegistration(username, displayName, promise);
58-
}
5959

60+
UiThreadUtil.runOnUiThread(
61+
new Runnable() {
6062
@Override
61-
public void error(@NonNull AuthenticationError authenticationError) {
62-
promise.reject(new Error("Unsupported platform"));
63+
public void run() {
64+
TSAuthentication.isPlatformAuthenticatorSupported(
65+
getReactApplicationContext(),
66+
new TSAuthCallback<Boolean>() {
67+
@Override
68+
public void success(Boolean aBoolean) {
69+
continueRegistration(username, displayName, promise);
70+
}
71+
72+
@Override
73+
public void error(@NonNull AuthenticationError authenticationError) {
74+
promise.reject(new Error("Unsupported platform"));
75+
}
76+
}
77+
);
6378
}
64-
}
65-
);
79+
});
6680
}
6781
private void continueRegistration(String username, String displayName, Promise promise) {
68-
TSAuthentication.register(
69-
getReactApplicationContext(),
70-
username,
71-
displayName,
72-
new TSAuthCallback<RegistrationResult>() {
82+
UiThreadUtil.runOnUiThread(
83+
new Runnable() {
7384
@Override
74-
public void success(RegistrationResult registrationResult) {
75-
WritableMap map = new WritableNativeMap();
76-
map.putString(registrationResult.result(), NAME);
77-
promise.resolve(map);
78-
}
85+
public void run() {
86+
TSAuthentication.register(
87+
getReactApplicationContext(),
88+
username,
89+
displayName,
90+
new TSAuthCallback<RegistrationResult>() {
91+
@Override
92+
public void success(RegistrationResult registrationResult) {
93+
WritableMap map = new WritableNativeMap();
94+
map.putString(registrationResult.result(), NAME);
95+
promise.resolve(map);
96+
}
7997

80-
@Override
81-
public void error(@NonNull AuthenticationError authenticationError) {
82-
promise.reject(NAME, authenticationError.toString());
98+
@Override
99+
public void error(@NonNull AuthenticationError authenticationError) {
100+
promise.reject(NAME, authenticationError.toString());
101+
}
102+
}
103+
);
83104
}
84-
}
85-
);
105+
});
86106
}
87107

88108
// Authentication
89109
@ReactMethod
90110
@NonNull public void authenticate(String username, Promise promise) {
91-
TSAuthentication.authenticate(
92-
getReactApplicationContext(),
93-
username,
94-
new TSAuthCallback<AuthenticationResult>() {
111+
UiThreadUtil.runOnUiThread(
112+
new Runnable() {
95113
@Override
96-
public void success(AuthenticationResult authenticationResult) {
97-
WritableMap map = new WritableNativeMap();
98-
map.putString(authenticationResult.result(), NAME);
99-
promise.resolve(map);
114+
public void run() {
115+
TSAuthentication.authenticate(
116+
getReactApplicationContext(),
117+
username,
118+
new TSAuthCallback<AuthenticationResult>() {
119+
@Override
120+
public void success(AuthenticationResult authenticationResult) {
121+
WritableMap map = new WritableNativeMap();
122+
map.putString(authenticationResult.result(), NAME);
123+
promise.resolve(map);
124+
}
125+
126+
@Override
127+
public void error(@NonNull AuthenticationError authenticationError) {
128+
promise.reject(NAME, authenticationError.toString());
129+
}
130+
}
131+
);
100132
}
133+
});
134+
}
101135

136+
@ReactMethod
137+
@NonNull public void signTransaction(String username, Promise promise) {
138+
UiThreadUtil.runOnUiThread(
139+
new Runnable() {
102140
@Override
103-
public void error(@NonNull AuthenticationError authenticationError) {
104-
promise.reject(NAME, authenticationError.toString());
141+
public void run() {
142+
TSAuthentication.signTransaction(
143+
getReactApplicationContext(),
144+
username,
145+
new TSAuthCallback<AuthenticationResult>() {
146+
@Override
147+
public void success(AuthenticationResult authenticationResult) {
148+
WritableMap map = new WritableNativeMap();
149+
map.putString(authenticationResult.result(), NAME);
150+
promise.resolve(map);
151+
}
152+
153+
@Override
154+
public void error(@NonNull AuthenticationError authenticationError) {
155+
promise.reject(NAME, authenticationError.toString());
156+
}
157+
}
158+
);
105159
}
106-
}
107-
);
160+
});
108161
}
109162
}
110163

example/android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ android {
7575

7676
namespace "com.tsauthenticationexample"
7777
defaultConfig {
78-
applicationId "com.transmitsecurity.authsdk-rn-example"
78+
applicationId "com.transmitsecurity.authsdk_rn_example"
7979
minSdkVersion rootProject.ext.minSdkVersion
8080
targetSdkVersion rootProject.ext.targetSdkVersion
8181
versionCode 1
51 MB
Binary file not shown.

example/android/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ buildscript {
66
minSdkVersion = 21
77
compileSdkVersion = 34
88
targetSdkVersion = 34
9-
9+
kotlin_version = "1.9.20"
1010
// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
1111
ndkVersion = "23.1.7779620"
1212
}
@@ -17,6 +17,7 @@ buildscript {
1717
dependencies {
1818
classpath("com.android.tools.build:gradle")
1919
classpath("com.facebook.react:react-native-gradle-plugin")
20+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
2021
}
2122
}
2223

example/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { SafeAreaView } from 'react-native';
3-
import TSAuthenticationSDKModule, { TSAuthenticationSDK } from 'react-native-ts-authentication';
3+
import TSAuthenticationSDKModule from 'react-native-ts-authentication';
44
import HomeScreen from './home';
55
import config from './config';
66
import localUserStore from './utils/local-user-store';

example/src/config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export default {
2-
clientId: "5nhc16n9f165t4gp0todzd37qzfr9oxq",
3-
domain: "shopcart.userid-stg.io",
4-
secret: "aa14b16a-87fb-43aa-8372-df130b25d1ad",
2+
clientId: "CLIENT_ID_FROM_PORTAL",
3+
domain: "ASSOCIATED_DOMAIN",
4+
secret: "SECRET_FROM_PORTAL", // Important! This is just for demo purposes. Never store your secret in the client side.
55
baseUrl: "https://api.transmitsecurity.io", // eu = "api.eu.transmitsecurity.io" ca = "api.ca.transmitsecurity.io"
66
}

example/src/logged-in.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*/
77

88
import React, { type ReactElement } from 'react';
9-
import { View, StyleSheet, Text, Button, TextInput } from 'react-native';
9+
import { View, StyleSheet, Text, Button } from 'react-native';
1010

1111
export type Props = {
1212
username: string;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
# Edit the following variables to match your keystore and app:
4+
KEY_STORE_ALIAS="YOUR_KEY_STORE_ALIAS"
5+
PATH_KEY_STORE_ALIAS_FOLDER="PATH_TO_KEY_STORE_FOLDER"
6+
KEY_STORE_FILE_NAME_IN_FOLDER="YOUR_KEY_STORE_FILE_NAME_IN_FOLDER"
7+
8+
cd $PATH_KEY_STORE_ALIAS_FOLDER
9+
# Export the signing certificate in DER format, hash, base64 encode, trim '=' and url encode
10+
11+
echo "Generating key hash for Android app..."
12+
keytool -exportcert -alias $KEY_STORE_ALIAS -keystore $KEY_STORE_FILE_NAME_IN_FOLDER | openssl sha256 -binary | openssl base64 | sed 's/=//g'| sed s/\\+/-/g | sed s/\\//_/g | sed -E s/=+\$//
13+
14+
echo "All done."

0 commit comments

Comments
 (0)