Ejiro Asiuwhu Software developer with industry experience in building scalable and performant applications that run on the web and smartphones with cutting-edge technology.

Using FaceID and TouchID in React Native and Expo

3 min read 1097

React Native Expo Biometric Faceid Touchid

In this biometric authentication tutorial, we’ll show you how to authenticate users with Face ID and Touch ID in a bare-bones React Native and Expo app.

We’ll use an Expo SDK, expo-local-authentication, to implement biometric authentication in our app. This uses the Platform APIs to access the device hardware so there is no chance of leaking any private information from the device.

With this SDK, we’ll implement local authentication with both facial recognition and fingerprint scanning in our React Native apps.

Throughout the course of this tutorial, we’ll cover:

Let’s get started!

What is biometric authentication?

Biometric authentication is a type of multifactor authentication (MFA) that employs data derived from the device user’s biological traits, such as facial characteristics, voice recognition, and fingerprints, to protect personal information and sensitive assets.

Mobile apps of all kinds use local biometric authentication. The best thing about biometric authentication is that it is performed entirely within the user’s device, so there is no risk of leaking sensitive data to a third-party API.

Aside from verifying user identities, biometrics can also serve as an additional layer of security alongside traditional sign-in methods, such as email/password.

Implementing biometric authentication in an Expo app

To start our tutorial, let’s go over the steps for installing, importing, and setting up biometric authentication in an Expo app.

Installation

Run the following command to install the expo-local-authentication library:

We made a custom demo for .
No really. Click here to check it out.

// with yarn
yarn add expo-local-authentication


// with npm
npm install expo-local-authentication

Import the package by adding the following line to the JavaScript or TypeScript file where you want to implement biometric authentication:

import * as LocalAuthentication from 'expo-local-authentication'

Check for device compatibility

First, we have to check whether the device hardware has support for biometrics. We’ll use the hasHardwareAsync method provided by the Expo LocalAuthentication package we just imported when the page is mounted:

// wherever the useState is located 
const [isBiometricSupported, setIsBiometricSupported] = React.useState(false);

// Check if hardware supports biometrics
  useEffect(() => {
    (async () => {
      const compatible = await LocalAuthentication.hasHardwareAsync();
      setIsBiometricSupported(compatible);
    })();
  });

// In our JSX we conditionally render a text to see inform users if their device supports
 <Text> {isBiometricSupported ? 'Your device is compatible with Biometrics' 
    : 'Face or Fingerprint scanner is available on this device'}
        </Text>

The hasHardwareAsync method returns a promise that resolves to a boolean hasHardwareAsync(): Promise<boolean> indicating whether the user’s device supports biometrics.

For cases where there’s no biometric support on the user’s device, you should consider enabling alternative methods, such as passwords, to authenticate users.

Check for biometric records

To check whether biometrics are saved on the user’s device, we’ll use the isEnrolledAsync method. This method returns a promise that resolves to a boolean isEnrolledAsync(): Promise<boolean>:

const handleBiometricAuth = async () => {
    const savedBiometrics = await LocalAuthentication.isEnrolledAsync();
      if (!savedBiometrics)
      return Alert.alert(
        'Biometric record not found',
        'Please verify your identity with your password',
        'OK',
        () => fallBackToDefaultAuth()
      );
}

Notice how we set the app to fall back to an alternative method of authentication when there’s no record of facial ID or fingerprint capabilities on the user’s device.

How biometric authentication works

To actually authenticate users via fingerprint scan or Touch ID/Face ID, we’ll use the LocalAuthentication.authenticateAsync method. This returns a promise resolving to an object containing success, which can be true or false.

Here’s an example of the payload returned when success is false:

Object {
    "error": "lockout",
    "message": "Too many attempts. Try again later.",
    "success": false,
  },

The authenticateAsync accepts options of type LocalAuthenticationOptions as an argument. Here’s what the options accept:

LocalAuthenticationOptions = {
    promptMessage?: string; 
    cancelLabel?: string;
    disableDeviceFallback?: boolean;
    fallbackLabel?: string;
  }

promptMessage

promptMessage is a message that’s shown alongside the TouchID or FaceID prompt:

Prompt Message Shown Along Biometric Id Prompt

cancelLabel

cancelLabel allows you to customize the default Cancel label that closes the biometrics prompt. Notice how the default Cancel has changed to Close biometrics prompt.

For this to work on some Android device, you may need to set the disableDeviceFallback to true.

Cancel Label Customize Default Prompt

disableDeviceFallback

disableDeviceFallback enables you to decide whether, after multiple attempts at facial recognition or fingerprint ID, the app should fall back to authenticate users with a device passcode. This option is set to false by default.

You may need to set the disableDeviceFallback option to true for your users to have access to the facial recognition biometrics API.

fallbackLabel

fallbackLabel allows you to customize the default passcode label. This option is only needed when disableDeviceFallback is false.

Here’s an example of how to use the authenticateAsync method:

const handleBiometricAuth = async () => {  
  const biometricAuth = await LocalAuthentication.authenticateAsync({
        promptMessage: 'Login with Biometrics',
        disableDeviceFallback: true,
      });
}

Permissions

On Android devices, permission are automatically added. On iOS, you’ll need to add infoPlist.NSFaceIDUsageDescription to your app.json file in your Expo app.

You have to place the NSFaceIDUsageDescription under ios.infoPlist.NSFaceIDUsageDescription in the app.json file. The value can be something like, APP_NAME needs to use Face ID / Touch ID to authenticate you.

NSFaceIDUsageDescription is a message that tells the user why the app is requesting the ability to authenticate with Face ID.

Implementing biometric authentication in a React Native app

To use this package in a bare-bones React Native app, you’ll need to install react-native-unimodules, which essentially enables you to use Expo modules in a React Native app.

Once you have successfully installed React Native unimodule, you can implement local authentication the same way we did with Expo.

Permissions in React Native

For iOS, you’ll need to add NSFaceIDUsageDescription to your info.plist file:

// info.plist
<key>NSFaceIDUsageDescription</key>
<string>$(PRODUCT_NAME) Authentication with TouchId or FaceID</string>

This key is required if your app uses APIs that access Face ID.

For Android, you’ll need to add the following lines of code to your AndroidManifest.xml file:

<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />

Conclusion

Local authentication has many use cases and I hope this tutorial makes it easier for you to implement biometric authentication with fingerprint (Touch ID) and facial recognition (Face ID) in your Expo and React Native apps.

The full code used in this tutorial is available on GitHub.

Feel free to drop a comment to let me know what you thought of this article. You can also find me on Twitter and GitHub. Thank you for reading!

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Ejiro Asiuwhu Software developer with industry experience in building scalable and performant applications that run on the web and smartphones with cutting-edge technology.

Leave a Reply