React Native Setup

Introduction

The Capsule SDK for React Native & Expo allows you to easily integrate secure and scalable wallet functionalities into your mobile applications. This guide covers the installation, setup, and usage of the Capsule SDK, including handling authentication flows via native passkeys or the webAuth portal.

Prerequisites

Installation

Dependency Installation

To install the Capsule SDK and required dependencies, use one of the following commands based on your package manager:

npm install @usecapsule/react-native-wallet @usecapsule/react-native-passkey @react-native-async-storage/async-storage node-libs-react-native react-native-crypto react-native-inappbrowser-reborn react-native-keychain react-native-modpow react-native-randombytes readable-stream

Setup

Follow these steps to properly set up Capsule SDK in your project, including iOS-specific configurations and necessary polyfill libraries.

iOS Setup

  1. Install pods:

bash
cd ios && pod install && cd ..
  1. Add capsule domains to your associated domains list(s):

    • Open ios/Runner.xcworkspace in Xcode.

    • Navigate to Signing & Capabilities and add the capability "Associated Domains".

    • Add a new associated domain for each environment:

      • Beta: webcredentials:app.beta.usecapsule.com

      • Prod: webcredentials:app.usecapsule.com

    • Send your full App ID to Capsule, formatted as <TEAM_ID>.bundleIdentifier.

Polyfill Libraries

  1. Add the following to your metro.config.js file:

metro.config.js
const nodeLibs = require("node-libs-react-native");
// Other imports

const config = {
  // Rest of your config
  resolver: {
    // Rest of your config.resolver
    extraNodeModules: {
      // Rest of your config.resolver.extraNodeModules
      ...nodeLibs,
      crypto: require.resolve("react-native-crypto"),
      stream: require.resolve("readable-stream"),
      process: require.resolve("process"),
    },
  },
};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);
  1. Create a shim.js file in the root of your project with the following contents:

shim.js
import { shim } from "@usecapsule/react-native-wallet";

if (typeof process === "undefined") {
  global.process = require("process");
} else {
  const bProcess = require("process");
  for (var p in bProcess) {
    if (!(p in process)) {
      process[p] = bProcess[p];
    }
  }
}

shim();
  1. Call your shim.js file in your index.js file:

index.js
import "./shim";

// Rest of your `index.js` file

Capsule Auth Flows

The following code samples demonstrate how to handle user authentication using either native passkeys or the webAuth portal. Each sample includes steps to check if a user exists, create a new user if necessary, and handle the verification process. After user creation, a verification email is sent, and the provided verification code must be handled appropriately to complete the authentication process. Choose the method that best fits your application's requirements.

Key Methods:

Common Methods

  • checkIfUserExists(email: string): Checks if a user already exists.

  • createUser(email: string): Creates a new user and sends a verification email.

Native Passkey Specific Methods

  • login(): Logs in the user using native passkeys.

  • verifyEmailBiometricsId(code: string): Verifies the user's email and retrieves the biometrics ID.

  • registerPasskey(email: string, biometricsId: string, userHandle: Uint8Array): Registers a new passkey for the user.

WebAuth Portal Specific Methods

  • initiateUserLogin(email: string, force: boolean): Initiates the login process via the webAuth portal.

  • waitForLoginAndSetup(): Waits for the user to complete login and setup via the webAuth portal.

  • verifyEmail(code: string): Verifies the user's email and retrieves the webAuth URL.

  • waitForAccountCreation(): Waits for the user to complete account creation via the webAuth portal.

NOTE: There are two hosted Capsule environments, Environment.BETA is for development and testing and Environment.PROD is for production. If you prefer, you can also reference Beta as Environment.DEVELOPMENT.

If you're referencing Environments as strings, for example in a .env file, you should refer to these environments as BETA and PRODUCTION, respectively.

Native Passkey Authentication

User Creation and Login

The following code snippet shows how to handle user creation and login using native passkeys. It checks if a user already exists, and if not, creates a new user and sends a verification email.

App.tsx
import { CapsuleMobile, Environment } from "@usecapsule/react-native-wallet";

// Initialize Capsule SDK with your API key and environment
const capsule = new CapsuleMobile(Environment.BETA, YOUR_API_KEY);

const handleCreateUser = async (email: string) => {
  try {
    // Check if the user already exists
    const userExists = await capsule.checkIfUserExists(email);

    if (userExists) {
      // User exists, initiate login process using native passkeys
      await capsule.login();
      console.log("User logged in successfully");
    } else {
      // User does not exist, create a new user
      await capsule.createUser(email);
      console.log("User created successfully. Verification email sent.");
    }
  } catch (error) {
    // Handle any errors that occur during the process
    console.error("Error during user creation/login:", error);
  }
};

Verification Step

This code snippet handles the verification code received by the user. It is only needed if a new user was created and needs to be verified.

App.tsx
// Handle the verification code received by the user
const handleVerifyCode = async (email: string, code: string) => {
  try {
    // Verify the user's email and retrieve the biometrics ID
    const biometricsId = await capsule.verifyEmailBiometricsId(code);
    const userHandle = new Uint8Array(16);
    crypto.getRandomValues(userHandle);

    // Register a new passkey for the user
    await capsule.registerPasskey(email, biometricsId, userHandle);
    console.log("User verified and passkey registered successfully");

    // Proceed with login after verification
    await capsule.login();
    console.log("User logged in successfully");
  } catch (error) {
    // Handle any errors that occur during verification
    console.error("Error during code verification:", error);
  }
};

WebAuth Portal Authentication

User Creation and Login

The following code snippet shows how to handle user creation and login via the webAuth portal. It checks if a user already exists, and if not, creates a new user and sends a verification email.

App.tsx
import { CapsuleMobile, Environment } from "@usecapsule/react-native-wallet";
import InAppBrowser from "react-native-inappbrowser-reborn";

// Initialize Capsule SDK with your API key and environment
const capsule = new CapsuleMobile(Environment.BETA, YOUR_API_KEY);

const handleCreateUser = async (email: string) => {
  try {
    // Check if the user already exists
    const userExists = await capsule.checkIfUserExists(email);

    if (userExists) {
      // User exists, initiate login process via webAuth portal
      const webAuthLoginUrl = await capsule.initiateUserLogin(email, true);

      // Open the webAuth URL in the in-app browser
      await InAppBrowser.open(webAuthLoginUrl);

      // Wait for the user to complete login and setup
      await capsule.waitForLoginAndSetup();

      // Close the in-app browser
      InAppBrowser.close();

      console.log("User logged in successfully via web portal");
    } else {
      // User does not exist, create a new user
      await capsule.createUser(email);
      console.log("User created successfully. Verification email sent.");
    }
  } catch (error) {
    // Handle any errors that occur during the process
    console.error("Error during user creation/login:", error);
  }
};

Verification Step

This code snippet handles the verification code received by the user. It is only needed if a new user was created and needs to be verified.

App.tsx
// Handle the verification code received by the user
const handleVerifyCode = async (email: string, code: string) => {
  try {
    // Verify the user's email and retrieve the webAuth URL
    const webAuthCreateUrl = await capsule.verifyEmail(code);

    // Open the webAuth URL in the in-app browser
    await InAppBrowser.open(webAuthCreateUrl);

    // Wait for the user to complete account creation
    await capsule.waitForAccountCreation();

    // Close the in-app browser
    InAppBrowser.close();
    console.log("User verified and account created successfully");
  } catch (error) {
    // Handle any errors that occur during verification
    console.error("Error during code verification:", error);
  }
};

Examples

For full working examples, please refer to our GitHub repository:

Troubleshooting

Known Issues and Resolutions

  • Issue: Errors during pod installation.

    • Resolution: Ensure CocoaPods is installed and updated (sudo gem install cocoapods).

  • Issue: Polyfill errors during build.

    • Resolution: Verify metro.config.js and shim.js are correctly configured.

Next Steps

This is a required step. After completing the initial setup, developers should now look into the customization options to enhance their integration. You can customize using the ConstructOpts that can be passed into the CapsuleMobile instance. Once you have customized your setup, proceed with the signing guide to learn how to sign transactions.

Customizing Your Integration

To customize and brand your integration, you can pass the ConstructOpts as the fourth parameter when instantiating the CapsuleMobile class. Here’s a brief example:

const capsule = new CapsuleMobile(Environment.BETA, YOUR_API_KEY, undefined, {
  //Web Portal customization.
  portalBackgroundColor: "#ffffff",
  portalPrimaryButtonColor: "#007bff",
  portalTextColor: "#000000",
  portalPrimaryButtonTextColor: "#ffffff",
  //Verification email customization.
  emailTheme: EmailTheme.light,
  emailPrimaryColor: "#007bff",
  //Your app URls
  linkedinUrl: "https://linkedin.com/company/example",
  githubUrl: "https://github.com/example",
  xUrl: "https://x.com/example",
  supportUrl: "https://example.com/support",
  homepageUrl: "https://example.com",
});

For advanced customization and additional features, check out the following guides:

Last updated