Skip to content

Commit

Permalink
Project import generated by Copybara.
Browse files Browse the repository at this point in the history
FolderOrigin-RevId: /usr/src/app/bi-sdk-react-native
  • Loading branch information
turnipdabeets authored and bi-ci-bot committed Feb 7, 2023
1 parent 0a5ab61 commit 19acaec
Show file tree
Hide file tree
Showing 71 changed files with 7,559 additions and 26,119 deletions.
2 changes: 1 addition & 1 deletion BeyondIdentityEmbeddedReactNative.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ Pod::Spec.new do |s|
s.source_files = "ios/**/*.{h,m,mm,swift}"

s.dependency "React-Core"
s.dependency "BeyondIdentityEmbedded", '1.0.4'
s.dependency "BeyondIdentityEmbedded", '2.0.0'

end
16 changes: 15 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0] - 2023-01-09
### Added
- A new expo config plugin to support development builds or prebuilds on expo

### Changed
- Rename instances of `Credential` to `Passkey`
- Update example app to authenticate with Beyond Identity by using Invocation Type `manual`
- Prefixed `Credential` properties to prevent name conflicts
- Nest tenantId, realmId, and identityId under appropriate objects in the `Credential`
- Update support links in the example app

### Fixed
- Scheme without a path is now recognized as a valid URL when binding a credential

## [1.0.0] - 2022-09-21
### Changed
- Updated the React Native SDK to support our newly released Secure Customer product. See the [documentation](https://developer.beyondidentity.com/docs/v1/sdks/react-native-sdk/overview) for more details.
- Updated the React Native SDK to support our newly released Secure Customer product. See the [documentation](https://developer.beyondidentity.com/docs/v1/sdks/react-native-sdk/overview) for more details.
107 changes: 93 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,29 @@

# Beyond Identity React Native SDK

Goodbye, passwords! The Beyond Identity SDK for React Native is a wrapper around our Native Embedded SDKs ([iOS](https://github.com/gobeyondidentity/bi-sdk-swift) and [Android](https://github.com/gobeyondidentity/bi-sdk-android)), which allows you to embed the Passwordless experience into your product. This SDK supports OIDC and OAuth2.
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

### Embedded SDK

Goodbye, passwords! The Beyond Identity SDK for React Native is a wrapper around our Native Embedded SDKs ([Android](https://github.com/gobeyondidentity/bi-sdk-android) and [iOS](https://github.com/gobeyondidentity/bi-sdk-swift)), which allows you to embed the Passwordless experience into your product. Users will not need to download the Beyond Identity Authenticator. This SDK supports OIDC and OAuth2.

## Installation

### Install the library:
### Using a [bare expo](https://docs.expo.dev/bare/hello-world/) or [react-native init](https://reactnative.dev/docs/environment-setup) app.

```sh
1. Install the SDK:
```
yarn add @beyondidentity/bi-sdk-react-native
```

or

```
npm i --save @beyondidentity/bi-sdk-react-native
npm install @beyondidentity/bi-sdk-react-native
```
2. Update Native Requirements in your ios/android folders:

> Note that this library is not compatible with Expo projects. This is because Expo's “managed” workflow does not allow usage of React Native libraries that introduce their own native code beyond the React Native APIs and components that are available in the Expo client app. If you have an Expo app and wish to use this project, you must `eject`.
### Update Native:
Please make sure your iOS project supports "minimum deployment target" 13.0 or later.

Make sure your `ios/Podfile` supports iOS 13 or later
In your `ios/Podfile` set:

```sh
platform :ios, '13.0'
Expand Down Expand Up @@ -64,17 +66,94 @@ allprojects {
}
```

### Using `expo`
> :warning: This package cannot be used in "Expo Go" because [it requires custom native code](https://docs.expo.io/workflow/customizing/). However you can leverage this library with a [development build](https://docs.expo.dev/development/introduction/) or [prebuild](https://docs.expo.dev/workflow/prebuild/).
1. Install the SDK:
```
expo install @beyondidentity/bi-sdk-react-native
```

2. Add the SDK [config plugin](https://docs.expo.dev/guides/config-plugins/) to the [plugins array](https://docs.expo.dev/versions/latest/config/app/#plugins) of your app.{json,config.js,config.ts}:
```
{
"expo": {
"plugins": [
["@beyondidentity/bi-sdk-react-native"],
]
}
}
```

3. Set native requirments either with [expo-build-properties](https://docs.expo.dev/versions/latest/sdk/build-properties/) or modify project [static files](https://docs.expo.dev/guides/config-plugins/#static-modification)

A. Modify the following static files

android/gradle.properties
```
android.minSdkVersion=26
```
ios/Podfile.properties.json
```
"ios.deploymentTarget": "13.0"
```

*or*

B. Add [expo-build-properties](https://docs.expo.dev/versions/latest/sdk/build-properties/) to your app.{json,config.js,config.ts}:


```
expo install expo-build-properties
```

```
{
"expo": {
"plugins": [
["@beyondidentity/bi-sdk-react-native"],
[
"expo-build-properties",
{
"android": {
"minSdkVersion": 26
},
"ios": {
"deploymentTarget": "13.0"
}
}
]
]
}
}
```

4. Next, rebuild your app as described in the ["Adding custom native code"](https://docs.expo.dev/workflow/customizing/) guide.

## Usage

```js
Check out the [Developer Documentation](https://developer.beyondidentity.com) and the [SDK API Documentation](https://gobeyondidentity.github.io/bi-sdk-react-native/) for more information.

### Setup

First, before calling the Embedded functions, make sure to initialize the SDK. This can be done where you register your root component.

```javascript
import { Embedded } from '@beyondidentity/bi-sdk-react-native';

Embedded.initialize(
biometricAskPrompt: string,
allowedDomains?: string[]
): Promise<Success>;
```

A set of functions are provided to you in this SDK. Check out the [documentation](https://developer.beyondidentity.com) for more information.
You may also add a listener to log native events with `Embedded.logEventEmitter` after initializing.

## Example App

## Run Examples
Clone the following repo and use the available comands to see the SDK in action!

To set up:
To set up (run this first):

```sh
yarn bootstrap
Expand Down
8 changes: 5 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,24 @@ def getExtOrIntegerDefault(name) {

android {
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')

defaultConfig {
minSdkVersion 26
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
versionCode 1
versionName "1.0"

}

buildTypes {
release {
minifyEnabled false
}
}

lintOptions {
disable 'GradleCompatible'
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
Expand Down Expand Up @@ -135,11 +137,11 @@ def kotlin_version = getExtOrDefault('kotlinVersion')

dependencies {
// noinspection GradleDynamicVersion
api 'com.facebook.react:react-native:+'
api 'com.facebook.react:react-native:0.70.+'

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

implementation "com.beyondidentity.android.sdk:embedded:1.0.2"
implementation "com.beyondidentity.android.sdk:embedded:2.0.0"

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2"
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import com.beyondidentity.embedded.sdk.EmbeddedSdk
import com.beyondidentity.embedded.sdk.models.Credential
import com.beyondidentity.embedded.sdk.models.CredentialState
import com.beyondidentity.embedded.sdk.models.CredentialState.ACTIVE
import com.beyondidentity.embedded.sdk.models.CredentialState.REVOKED
import com.beyondidentity.embedded.sdk.models.Passkey
import com.beyondidentity.embedded.sdk.models.State
import com.beyondidentity.embedded.sdk.models.State.ACTIVE
import com.beyondidentity.embedded.sdk.models.State.REVOKED
import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter


private const val EMBEDDED_KEYGUARD_REQUEST = 2314
private const val INITIALIZE_ERROR = "Please call Embedded.initializeBiSdk first"
private const val SUCCESS = "success"
Expand Down Expand Up @@ -70,18 +69,18 @@ class BiSdkReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
fun authenticate(
url: String,
credentialID: String,
passkeyId: String,
promise: Promise
) {
if (!isEmbeddedSdkInitialized) {
promise.reject(Throwable(INITIALIZE_ERROR))
return
}

EmbeddedSdk.authenticate(url, credentialID) { authResult ->
EmbeddedSdk.authenticate(url, passkeyId) { authResult ->
authResult.onSuccess { authResponse ->
val n = WritableNativeMap()
n.putString("redirectURL", authResponse.redirectUrl ?: "")
n.putString("redirectUrl", authResponse.redirectUrl ?: "")
n.putString("message", authResponse.message ?: "")
promise.resolve(n)
}
Expand All @@ -90,16 +89,16 @@ class BiSdkReactNativeModule(reactContext: ReactApplicationContext) :
}

@ReactMethod
fun bindCredential(url: String, promise: Promise) {
fun bindPasskey(url: String, promise: Promise) {
if (!isEmbeddedSdkInitialized) {
promise.reject(Throwable(INITIALIZE_ERROR))
return
}

EmbeddedSdk.bindCredential(url) { bindResult ->
EmbeddedSdk.bindPasskey(url) { bindResult ->
bindResult.onSuccess { bindResponse ->
val n = WritableNativeMap()
n.putMap("credential", makeCredentialMap(bindResponse.credential))
n.putMap("passkey", makePasskeyMap(bindResponse.passkey))
n.putString("postBindingRedirectUri", bindResponse.postBindingRedirectUri ?: "")
promise.resolve(n)
}
Expand All @@ -108,33 +107,33 @@ class BiSdkReactNativeModule(reactContext: ReactApplicationContext) :
}

@ReactMethod
fun deleteCredential(id: String, promise: Promise) {
fun deletePasskey(id: String, promise: Promise) {
if (!isEmbeddedSdkInitialized) {
promise.reject(Throwable(INITIALIZE_ERROR))
return
}

EmbeddedSdk.deleteCredential(id) { deleteCredResult ->
deleteCredResult.onSuccess {
EmbeddedSdk.deletePasskey(id) { deleteResult ->
deleteResult.onSuccess {
promise.resolve(id)
}
deleteCredResult.onFailure { t -> promise.reject(t) }
deleteResult.onFailure { t -> promise.reject(t) }
}
}

@ReactMethod
fun getCredentials(promise: Promise) {
fun getPasskeys(promise: Promise) {
if (!isEmbeddedSdkInitialized) {
promise.reject(Throwable(INITIALIZE_ERROR))
return
}
EmbeddedSdk.getCredentials { credResult ->
credResult.onSuccess { credentials ->
val credentialsArray = WritableNativeArray()
credentials.map { makeCredentialMap(it) }.forEach { credentialsArray.pushMap(it) }
promise.resolve(credentialsArray)
EmbeddedSdk.getPasskeys { getResult ->
getResult.onSuccess { passkeys ->
val passkeysArray = WritableNativeArray()
passkeys.map { makePasskeyMap(it) }.forEach { passkeysArray.pushMap(it) }
promise.resolve(passkeysArray)
}
credResult.onFailure { t ->
getResult.onFailure { t ->
promise.reject(t)
}
}
Expand Down Expand Up @@ -175,15 +174,15 @@ class BiSdkReactNativeModule(reactContext: ReactApplicationContext) :
}

@ReactMethod
fun isBindCredentialUrl(
fun isBindPasskeyUrl(
url: String,
promise: Promise
) {
if (!isEmbeddedSdkInitialized) {
promise.reject(Throwable(INITIALIZE_ERROR))
return
}
promise.resolve(EmbeddedSdk.isBindCredentialUrl(url))
promise.resolve(EmbeddedSdk.isBindPasskeyUrl(url))
}

@ReactMethod
Expand Down Expand Up @@ -222,44 +221,44 @@ class BiSdkReactNativeModule(reactContext: ReactApplicationContext) :
}
}

private fun makeCredentialMap(credential: Credential): WritableNativeMap {
private fun makePasskeyMap(passkey: Passkey): WritableNativeMap {
val map = WritableNativeMap()
map.putString("id", credential.id)
map.putString("localCreated", credential.localCreated.toString())
map.putString("localUpdated", credential.localUpdated.toString())
map.putString("apiBaseUrl", credential.apiBaseURL.toString())
map.putString("tenantId", credential.tenantId)
map.putString("realmId", credential.realmId)
map.putString("identityId", credential.identityId)
map.putString("keyHandle", credential.keyHandle)
map.putString("state", credentialStateToPascalCase(credential.state))
map.putString("created", credential.created.toString())
map.putString("updated", credential.updated.toString())
map.putString("id", passkey.id)
map.putString("localCreated", passkey.localCreated.toString())
map.putString("localUpdated", passkey.localUpdated.toString())
map.putString("apiBaseUrl", passkey.apiBaseUrl.toString())
map.putString("keyHandle", passkey.keyHandle)
map.putString("state", passkeyStateToPascalCase(passkey.state))
map.putString("created", passkey.created.toString())
map.putString("updated", passkey.updated.toString())

val realmMap = WritableNativeMap()
realmMap.putString("displayName", credential.realm.displayName)
realmMap.putString("id", passkey.realm.id)
realmMap.putString("displayName", passkey.realm.displayName)
map.putMap("realm", realmMap)

val identityMap = WritableNativeMap()
identityMap.putString("displayName", credential.identity.displayName)
identityMap.putString("username", credential.identity.username)
identityMap.putString("primaryEmailAddress", credential.identity.primaryEmailAddress)
identityMap.putString("id", passkey.identity.id)
identityMap.putString("displayName", passkey.identity.displayName)
identityMap.putString("username", passkey.identity.username)
identityMap.putString("primaryEmailAddress", passkey.identity.primaryEmailAddress)
map.putMap("identity", identityMap)

val tenantMap = WritableNativeMap()
tenantMap.putString("displayName", credential.tenant.displayName)
tenantMap.putString("id", passkey.tenant.id)
tenantMap.putString("displayName", passkey.tenant.displayName)
map.putMap("tenant", tenantMap)

val themeMap = WritableNativeMap()
themeMap.putString("logoLightUrl", credential.theme.logoUrlLight.toString())
themeMap.putString("logoDarkUrl", credential.theme.logoUrlDark.toString())
themeMap.putString("supportUrl", credential.theme.supportUrl.toString())
themeMap.putString("logoLightUrl", passkey.theme.logoLightUrl.toString())
themeMap.putString("logoDarkUrl", passkey.theme.logoDarkUrl.toString())
themeMap.putString("supportUrl", passkey.theme.supportUrl.toString())
map.putMap("theme", themeMap)

return map
}

private fun credentialStateToPascalCase(state: CredentialState) =
private fun passkeyStateToPascalCase(state: State) =
when (state) {
ACTIVE -> "Active"
REVOKED -> "Revoked"
Expand Down
Loading

0 comments on commit 19acaec

Please sign in to comment.