The Stytch React Native SDKs provide the easiest way for you to use Stytch in your React Native projects. We provide separate SDKs for Expo managed workflows as well as bare React Native projects to ensure ease of installation and use, as well as compatibility with iOS and Android builds. Using the SDKs allows you to easily authenticate your users without adding extra endpoints to your backend.
Compatibility and requirements
The Expo SDK is compatible with all actively supported Expo versions (currently Expo 41+).
The Expo SDK also supports all versions of iOS and Android supported by Expo (currently Android 5+ and iOS 11+)
The React Native SDK is compatible with React Native 0.60+
Supported authentication products
Email magic links
One-time passcodes
Biometrics
Passwords
Session management
User management
Installation
Install the relevant package(s) as a project dependency via npm or yarn.
If you are using Stytch's Biometrics or OAuth product, you will also need to install @stytch/react-native-modules. If you are using an "ejected" Expo setup (required for installing packages with custom native modules, learn more in the Expo docs), you will also need to install @react-native-async-storage/async-storage and react-native-keychain.
Initialize the SDK by creating a new StytchClient object provided in the package. We recommend storing the created client instance in a common file to use it in JavaScript methods such as Redux actions.
You do not need to manually link, but will need to run pod install if you are using @stytch/react-native.
StytchClient parameters
public_token*string
Provide the public token from the Stytch dashboard. This value is safe to embed client side.
At the root level of your application, initialize a new StytchProvider object using your public token. to provide all components with access to the StytchClient as well as User and Session data via hooks.
StytchProvider props
stytch*StytchClient | null
Provide the previously created StytchClient object.
To authorize the Stytch SDK to run in your application, you must first add an Authorized Environment Bundle ID to your Stytch SDK Configuration.
Any application published to the Apple App Store or the Google Play Store must have a unique ID. In iOS development, this is referred to as a bundle identifier, and in Android it is referred to as the Application ID or package name.
If the bundle identifier / package name does not match the Authorized Environment Bundle ID in your Stytch SDK Configuration, then you will receive an invalid_mobile_identifier error on any requests made through the SDK. If you are encountering this error, ensure that you've followed the steps in this configuration correctly.
For bare React Native projects, the process takes a few extra steps, and there are separate processes for updating iOS bundle identifier vs. the Android package name.
For iOS, you first open the general settings for the project in Xcode. To get there, open the project workspace, and select the appname project from the project navigator. Once you've opened the general settings for the project, simply update the Bundle Identifier field.
For Android, there a number of steps. Firstly, you'll need to rename the folder structure inside android/app/src/main/java to reflect the package name for your project. If you had initialized your project with the name HelloWorld, you would find two files MainActivity.java and MainApplication.java inside android/app/src/main/java/com/helloworld. If you wanted to change your package name to com.myapp.test you'd have to update the folder structure so that those two files were insideandroid/app/src/main/java/com/myapp/test. After you've updated your folder structure, you need to update:
The package name on line 1 of MainActivity.java
The package name on line 1 of MainApplication.java
Line 2 of /android/app/src/main/AndroidManifest.xml
The package value for android_build_config and android_resource in /android/app/BUCK
The applicationId value in defaultConfig for the /android/app/build.gradle file.
One-time passcodes can be sent via email, phone number, or WhatsApp. One-time passcodes allow for a quick and seamless login experience on their own, or can layer on top of another login product like Email magic links to provide extra security as a multi-factor authentication (MFA) method.
Methods
To call these methods, One-time passcodes must be enabled in the SDK Configuration page of the Stytch dashboard.
Login or create via SMS
Wraps Stytch's login_or_create via SMS API endpoint. Call this method to send an SMS passcode to new or existing users.
Wraps Stytch's send via SMS API endpoint. Call this method to send an SMS passcode to existing users.
This method is also used when you need to add a phone number to an existing Stytch User. If there is a currently valid Stytch session, and the user inputs a phone number that does not match one on their Stytch User object, upon successful authentication the new phone number will be added to the existing user. Note, this does expose a potential account enumeration vector, see our article on preventing account enumeration for more details.
Wraps Stytch's send via email API endpoint. Call this method to send an email passcode to existing users.
This method is also used when you need to add a phone number to an existing Stytch User. If there is a currently valid Stytch session, and the user inputs a phone number that does not match one on their Stytch User object, upon successful authentication the new phone number will be added to the existing user. Note, this does expose a potential account enumeration vector, see our article on preventing account enumeration for more details.
Wraps Stytch's send via WhatsApp API endpoint. Call this method to send an WhatsApp passcode to existing users.
This method is also used when you need to add a phone number to an existing Stytch User. If there is a currently valid Stytch session, and the user inputs a phone number that does not match one on their Stytch User object, upon successful authentication the new phone number will be added to the existing user. Note, this does expose a potential account enumeration vector, see our article on preventing account enumeration for more details.
The React Native SDK provides methods to send and authenticate magic links that you can connect to your own UI. Use these to quickly get up and running with magic links.
Configuration
Email Magic Links require enabling deeplinks in your application. This process is different for Expo managed versus bare (or vanilla) workflows
While the React Native guide contains the full details, below is a summary of the steps required:
iOS Setup
Add the following to AppDelegate.m
// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this above '@end':
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
return [RCTLinkingManager application:application openURL:url options:options];
}
If your app is using Universal Links you'll need to add the following code as well:
Add the scheme to your project configuration. The easiest way to do this is with the uri-scheme package by running the following:
npx uri-scheme add myapp --ios
If you want to do it manually, open the project (e.g. SimpleApp/ios/SimpleApp.xcworkspace) in Xcode. Select the project in sidebar and navigate to the info tab. Scroll down to "URL Types" and add a new one. In the new URL type, set the identifier and the URL scheme to your desired URL scheme.
To make sure Universal Links work in your app, you will also need to setup Associated Domains on your server.
If you're using React Navigation within a hybrid app - an iOS app that has both Swift/Objective-C and React Native parts - you may be missing the RCTLinkingIOS subspec in your Podfile, which is installed by default in new React Native projects. To add this, ensure your Podfile looks like the following:
pod 'React', :path => 'docs/node_modules/react-native', :subspecs => [
. . . // other subspecs
'RCTLinkingIOS',
. . .
]
Android Setup
To configure the external linking in Android, you create a new intent in the manifest.
The easiest way to do this is with the uri-scheme package:
npx uri-scheme add myapp --android
If you want to add it manually, open up SimpleApp/android/app/src/main/AndroidManifest.xml, and make the following adjustments:
Set launchMode of MainActivity to singleTask in order to receive intent on existing MainActivity (this is the default, so you may not need to actually change anything).
Add the new <intent-filter> inside the MainActivity entry with a View type action:
Similar to Universal Links on iOS, you can also use a domain to associate the app with your website on Android by Verifying Android App Links. First, you need to configure your AndroidManifest.xml:
Add android:autoVerify="true" to your <intent-filter> entry.
Add your domain's scheme and host in a new <data> entry inside the <intent-filter>
The SDK provides methods that can be used to send magic links and authenticate tokens in the links later.
To call these methods, Email Magic Links must be enabled in the SDK Configuration page of the Stytch dashboard.
Send
The Send method wraps the send Email Magic Link API endpoint. This method requires that the user already exist within Stytch before a magic link may be sent. This method is useful for gating your login flow to only pre-created users, e.g. an invite or waitlist.
This method is also used when you need to add an email address to an existing Stytch User. If there is a currently valid Stytch session, and the user inputs an email address that does not match one on their Stytch User object, upon successful authentication the new email address will be appended to the emails array. Note, this does expose a potential account enumeration vector, see our article on preventing account enumeration for more details.
The React Native SDK provides methods for creating, storing, and authenticating password based users, as well as support for account recovery (password reset) and account deduplication with passwordless login methods.
Methods
The SDK provides methods that can be used to create and authenticate password based users.
To call these methods, Passwords must be enabled in the SDK Configuration page of the Stytch dashboard.
Create
The send method wraps the create Password API endpoint.
This method allows you to check whether or not the user’s provided password is valid, and to provide feedback to the user on how to increase the strength of their password. All passwords must pass the strength requirements to be accepted as valid.
The strengthCheck method wraps the strength_check Password API endpoint.
Biometric authentication enables your users to leverage their devices' built-in biometric authenticators such as FaceID and TouchID for quick and seamless login experiences.
Configuration
Biometrics requires importing native modules into your React Native or Expo app. If you are using Expo, you may need to review using native modules in the Expo docs.
After installing the latest version of @stytch/react-native or @stytch/react-native-expo, you'll also need to install the latest version of @stytch/react-native-modules. You'll then need to run pod install from the ios folder in order to install the native modules required for biometrics.
Stytch's Biometrics product supports iOS 13.0+ and Android M+
Important: When testing your biometrics implementation with an iOS emulator, you must use iOS version 13 or 14. The minimum target for the Stytch SDKs is iOS 13.0, and biometrics do not work on emulators running iOS 15. This should not be an issue on real devices for testing and production.
Methods
The SDK provides methods that can be used to authenticate users with biometric factors. Biometric factors must first be added to an existing user, and then later used as a primary or secondary authentication factor. To call these methods, Biometrics must be enabled in the SDK Configuration page of the Stytch dashboard.
Register
If an active session is present, this method will add a biometric registration for the current user. The user will later be able to start a new session with biometrics or use biometrics as an additional authentication factor.
If a valid biometric registration exists, this method confirms the current device owner via the device's built-in biometric reader and returns a session object by either starting a new session or adding a biometric factor to an existing session.
Indicates whether or not the Keystore is available on the device. This will always return true for iOS devices. A percentage of Android devices will return false. To learn more about the implications of the Android Keystore being unavailable, read our Android Keystore resource.
Indicates if there is an existing biometric registration on device. This method can be used to determine whether or not to show biometric login or registration options.
There was an error with the biometric sensor on the device. This usually means that the biometric sensor is currently unavailable for use.
device_credentials_not_allowed
This means that allowDeviceCredentials was set to false in register(), but allowDeviceCredentials was set to true in authenticate(). Consider changing these parameters to be the same.
device_hardware_error
The device's hardware does not support biometrics. This might be because the hardware is unavailable for use, or there is a security vulnerability with the hardware.
internal_error
An internal error has occurred. Please contact Stytch if this occurs.
key_invalidated
The biometrics enrollment on the device has changed, so biometric authentication cannot use the current registration. Try deleting the registration and authenticating again.
keystore_unavailable
The Android keystore is unavailable on the device. Learn more about the Android Keystore here.
no_biometrics_enrolled
No biometric factor is enrolled on the device. Consider encouraging the user to enroll in biometrics on their device.
no_biometrics_registration
No valid biometrics registration exists on the device. Please use the register method to create a new biometric registration.
session_expired
There is currently no valid session token. Consider encouraging the user to log in.
user_cancellation
The user canceled the biometric prompt. Consider providing other methods of authentication, and a way for the user to return to the biometric prompt.
user_locked_out
The user has been locked out from authentication using biometrics due to too many failed attempts. Consider providing other methods of authentication.
OAuth
OAuth is a popular authentication framework that delegates authentication to an external identity provider (often shortened to IdP) like Google, Facebook, Apple, and Microsoft. A user relies on their membership from that provider to sign in instead of creating another password, and developers can enrich their users' experiences with the information shared by the providers.
The React Native SDK provides methods to start and authenticate OAuth flows that you can connect to your own UI.
Configuration
OAuth requires importing native modules into your React Native or Expo app. If you are using Expo, you may need to review using native modules in the Expo docs.
After installing the latest version of @stytch/react-native or @stytch/react-native-expo, you'll also need to install the latest version of @stytch/react-native-modules. You'll then need to run pod install from the ios folder in order to install the native modules required for OAuth.
Methods
The SDK provides methods that can be used to get the URL to start an OAuth flow and authenticate tokens in the links later.
To call these methods, OAuth must be enabled in the SDK Configuration page of the Stytch dashboard.
Start
The oauth.$provider.start() methods start OAuth flows by redirecting the browser to one of Stytch's oauth start endpoints. The method will also generate a PKCE code_verifier and store it in local storage on the device (See the PKCE OAuth guide for details). If your application is configured to use a custom subdomain with Stytch, it will be used automatically.
Once a user has successfully logged in, the SDK can be used to view and manage that user's information, add additional authentication factors, or delete factors that are no longer used.
Methods
To call these methods, Manage user data must be enabled in the SDK Configuration page of the Stytch dashboard.
Get user
The SDK provides two methods for getting a user. The recommended approach is to use the synchronous method, user.getSync, and listen to changes with the user.onChange method.
If logged in, the user.getSync method returns the cached user object. Otherwise it returns null. This method does not refresh the user's data. The @stytch/react-native and @stytch/react-native-expo libraries provide the useStytchUser hook that implements these methods for you to easily access the user and listen for changes.
The user.onChange method takes in a callback that gets called whenever the user object changes. It returns an unsubscribe method for you to call when you no longer want to listen for such changes.
The asynchronous method, user.get, wraps the get user endpoint. It fetches the user's data and refreshes the cached object if changes are detected. The Stytch SDK will invoke this method automatically in the background, so you probably won't need to call this method directly.
Example
Vanilla
import React from 'react';
import { useStytchUser } from '@stytch/react-native';
export const Home = () => {
const { stytchUser } = useStytchUser();
return stytchUser ? <p>Welcome, {stytchUser.name.first_name}</p> : <p>Log in to continue!</p>;
};
Update user
Wraps Stytch's update user endpoint. Use this method to change the user's name, untrusted metadata, and attributes.
You can listen for successful user updates anywhere in the codebase with the stytch.user.onChange() method or useStytchUser() hook.
Note: If a user has enrolled another MFA method, this method will require MFA. See the Multi-factor authentication section for more details.
These methods cannot be used to remove all factors from a user. A user must have at least one email, phone number, or OAuth provider associated with their account at all times, otherwise they will not be able to log in again.
You can listen for successful user updates anywhere in the codebase with the stytch.user.onChange() method or useStytchUser() hook.
Note: If a user has enrolled another MFA method, this method will require MFA. See the Multi-factor authentication section for more details.
The SDK may be used to check whether a user has a cached session, view the current session, refresh the session, and revoke the session. To authenticate a session on your backend, you must use either the Stytch API or a Stytch Backend SDK.
Methods
Get session
The SDK provides the session.getSync method to retrieve the current session. The session.onChange method can be used to listen to session changes.
If logged in, the session.getSync method returns the cached session object. Otherwise it returns null. The @stytch/react-native and @stytch/react-native-expo libraries provide the useStytchSession hook that implements these methods for you to easily access the session and listen for changes.
The session.onChange method takes in a callback that gets called whenever the user object changes. It returns an unsubscribe method for you to call when you no longer want to listen for such changes.
Wraps Stytch's authenticate Session endpoint and validates that the session issued to the user is still valid. The SDK will invoke this method automatically in the background. You probably won't need to call this method directly. It's recommended to use session.getSync and session.onChange instead.
Returns the session_token and session_jwt for the active session. Otherwise retuns null.
Example
Vanilla
import React, { useEffect } from 'react';
import { useStytch, useStytchSession } from '@stytch/react-native';
export const SendSessionTokensToBackend = () => {
const stytchClient = useStytch();
const { session } = useStytchSession();
// this will update the sessionTokens everytime the session updates (on login, session refresh, MFA, etc)
const sessionTokens = useMemo(() => {
return stytchClient.session.getTokens();
}, [session]);
// This useEffect block will trigger anytime the sessionTokens change
useEffect(() => {
if (!!sessionTokens) {
console.log('session token', tokens.session_token);
console.log('session jwt', tokens.session_jwt);
// Do something with tokens
}
}, [sessionTokens]);
return null;
};
Update session
Update a user's session tokens to hydrate a front-end session from the backend. For example, if you log your users in with one of our backend SDKs, you can pass the resulting session_token and session_jwt to this method to prime the frontend SDK with a valid set of tokens. You must then make an authenticate call to authenticate the session tokens and retrieve the user's current session.
Example
Vanilla
import React, { useCallback, useEffect } from 'react';
import { useStytch, useStytchUser } from '@stytch/react-native';
export const App = () => {
const stytchClient = useStytch();
const user = useStytchUser();
useEffect(() => {
if (user) {
// redirect to logged in experience
}
}, [user]);
const authenticate = useCallback(() => {
stytchClient.session.updateSession({
session_token: 'a session token from your backend',
session_jwt: 'a session JWT from your backend',
});
stytchClient.session.authenticate({ session_duration_minutes: 60 });
}, [stytchClient]);
return <button onClick={authenticate}>Hydrate session</button>;
};
Resources
Migration Guide
@stytch/react-native-expo@0.7.0 and @stytch/react-native@0.6.0 updates the useStytchUser and useStytchSession hooks.
The useStytchUser and useStytchSession hooks now return envelope objects, { user, fromCache } and { session, fromCache } respectively.
On first render, the SDK will read the user or session out of local storage, and serve them with fromCache: true.
The SDK will make network requests to update the user and session objects, and serve them with fromCache: false.
Android Keystore Considerations
When a user registers a biometric factor with Stytch, our SDKs rely on the device keystore to securely store sensitive data associated with the authentication factor.
Unfortunately, Android KeyStore has had significant functionality and reliability issues throughout its lifespan in the Android ecosystem. Not all devices that support biometrics have suitable Keystore implementations that can be relied on.
The official Tink documentation references this instability (1, 2) and they have provided developers with a mechanism to ensure the device you're operating will not encounter implementation problems (3).
If KeyStore is found to be unreliable, this code will fall back to storing sensitive information in the application sandbox, as opposed to the KeyStore. This is not itself a security vulnerability, as the Android platform enforces access barriers between applications to prevent unauthorized access to your application's private data.
That said, this method comes with less security guarantees than using KeyStore, such as protecting the data in the event of a privilege escalation in Android. There are some things you should watch out for when developing an application that allows this fallback.
The biggest issue which would potentially expose your application's sandbox data is writing insecure IPC (inter-process communication). Developers can accidentally create an arbitrary file read vulnerability by misusing Android IPC (4), or by writing sensitive information to public storage (sdcard). Be extra cautious with any functionality that accepts arbitrary file paths as arguments, which may allow an attacker to redirect the flow of data to an area they can access it.