Peter Ekene Eze Learn, Apply, Share

Implementing secure passwordless authentication in React Native apps with Auth0

7 min read 2170

Passwordless authentication can be understood as the process of verifying the identity of a user without the provision of a password. It is okay to assert that any method that verifies users without the use of a password falls under this category. Some more passwordless techniques are:

  • Biometric authentication
  • Use of authenticator apps
  • Knowledge-based authentication and so on

Why passwordless?

Passwords are generally hard to remember and vulnerable to phishing attacks. Let’s add some numbers to it, according to Retruster statistical analysis, here’s the state of phishing attacks in 2019 alone:

  • The average financial cost of a data breach is $3.86m (IBM)
  • Phishing accounts for 90% of data breaches
  • 15% of people successfully phished will be targeted at least one more time within the year
  • BEC scams accounted for over $12 billion in losses (FBI)
  • Phishing attempts have grown 65% in the last year
  • Around 1.5m new phishing sites are created each month (Webroot)
  • 76% of businesses reported being a victim of a phishing attack in the last year
  • 30% of phishing messages get opened by targeted users (Verizon)

The events of recent times as it relates to data breaches and phishing attacks forced us to look for more secure ways to handle authentication and identity verification. This brings us to — passwordless authentication.

According to Ant Allan, Vice President Analyst at Gartner:

By 2022, Gartner predicts that 60% of large and global enterprises, and 90% of midsize enterprises, will implement passwordless methods in more than 50% of use cases — up from 5% in 2018

This makes now a great time to start preparing for the seemingly inevitable fact that eventually, the world will go passwordless.

What we’ll build

In this post, I intend to show you how you can implement passwordless authentication in your React Native applications using Auth0. We will start off from scratch and build out a login page that verifies a user’s identity and returns the necessary credentials needed to access the app and perform other actions:

react native application using auth0

Prerequisites

Before we jump into it, let’s clear the air on what you need to know/have before we get started!

  • This post will be written with the assumption that you haven’t done passwordless authentication in the past, so if this is your first time you’ll be fine, however, prior knowledge of authentication principles will be a plus
  • Auth0 — We’ll be using Auth0 as the sole auth provider for the sample application. Prior knowledge of Auth0 will be very helpful, however, it is not a barrier to follow along as we will be discussing it all in detail
  • Twilio – You’ll need a Twilio account to power our SMS service functionality
  • Some useful tools to install — if you don’t already have Node installed on your computer, go ahead and install it from here along with the Auth0 React Native SDK, and webview. I’ll show you how to install them shortly

Getting started

First, let’s create a React Native project. If this is your first time working with React Native, be sure to install the required dependencies and follow these steps accordingly.

Install the React Native CLI tool using npm like so:

npm install -g react-native-cli

Afterward, go ahead and run these React Native commands to create and start a new project.

Create a new project and start the server:

react-native init auth

cd auth && npx react-native run-ios // Start the iOS simulator
// OR
cd auth && npx react-native run-android // Start the android emulator

If you have Xcode or Android Studio installed then the commands above will run the project and you should have the simulator show up on the screen like this:

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

initial set up on simulator

Here I’m using Xcode.

Now that we have the project created and running locally, let’s install some packages that we’ll need to build the app:

  • First, you need to install the Auth0 React Native SDK that we will use for authentication and the React native webview library:
npm install react-native-auth0 react-native-webview
//OR
yarn add react-native-auth0 react-native-webview
  • Then install the iOS app pods with Cocoapods:
cd ios && pod install

Passwordless flow

Using Auth0, here’s how the passwordless implementation will work. Auth0’s passwordless authentication flow is a two-step verification system that takes a user’s email address or phone number. For cases where you decide to authenticate by phone, you can initiate the flow by requesting for a code using the user’s phone number, an auth code will be sent to their phone number:

auth0.auth
  .passwordlessWithSMS({
    phoneNumber: '+5491159991000',
  })
  .then(console.log)
  .catch(console.error);

When authenticating with email, you can initiate the flow by requesting for a link to be sent to the user’s email address. When the user clicks on the link, it’ll take them to your auth0 domain on the browser and then redirect to your application. Consequently, you can request for a code to be sent to the email too:

auth0.auth
  .loginWithEmail({
    email: 'info@auth0.com',
    code: '123456',//for code
    link: 'your-link.com' // for email
  })
  .then(console.log)
  .catch(console.error);

Moving forward in this post we’ll continue with the phone authentication flow.

App configuration

You need to make your Android and iOS applications aware that an authentication result will be received from Auth0. This configuration makes it possible for Auth0 to communicate with your application and in the case of email link scenarios, redirect users from your browser to the app. The configuration is different for Android and iOS, but I’ll only cover iOS configuration in this tutorial. You can learn more about it and how to configure it for Android in the React Native docs.

Inside the iOS folder, find the file AppDelegate.[m] and add the following snippet to it:

#import <React/RCTLinkingManager.h>

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
  return [RCTLinkingManager application:application openURL:url
                      sourceApplication:sourceApplication annotation:annotation];
}

Inside the iOS folder, open the Info.plist file and locate this snippet:

<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>

Below it, register a URL type entry by adding this exact snippet:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>None</string>
        <key>CFBundleURLName</key>
        <string>auth0</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
        </array>
    </dict>
</array>

Set up an Auth0 project

Now that we are done with the application configurations, let’s build our React Native app. Before we start writing the application code, let’s set up a project in Auth0 following these steps:

Step 1: Create an Auth0 account

If you don’t have one yet, create a free Auth0 account here and log into your dashboard:

create a free Auth0 account page

Step 2: Create a new application

Login to your dashboard and navigate to the Applications tab on the sidebar, click the Create Application button to create a new Auth0 app:

create a new application

Step 3: Select the application type

In the next screen you select the type of application you’re building and give it a name. In our case, we are building a native mobile application and call it “React Native App”:

select app type

Step 4: Select an SDK

In our case, select React Native from the screen below:

select native sdk

Step 5: View credentials

Now that your application is created, navigate to the settings menu to review your applications credentials:

view credentials

Keep these credentials safe as we’ll be needing them shortly in the app.

Set up a passwordless grant

Auth0 enforces that you use appropriate grants for every authentication flow implemented. In our case, we are using the passwordless authentication flow and we need to enable that grant type on the dashboard.

To enable the passwordless grant type, select your React Native app on your dashboard, click on the Project Settings, scroll down, and expand Advanced Settings, click on the Grant Types tab and tick the passwordless grant type:

grant types

Enable SMS connection

We are authenticating via phone, as a result, we need to enable an SMS connection on the application, click on the Connections tab on the sidebar and select Passwordless. Toggle the SMS button to enable SMS connection:

enable sms connection

Set up Twilio SSID

Next, click on the SMS card to configure the SMS connection with your Twilio credentials. If you don’t have a Twilio account, sign up for one here and retrieve your SSID and token:

twilliosignup

When you’ve verified your account, log in, and create a new project like so:

create a new account

When you sign up on Twilio for a trial account, you will get access to about $15 you can use to purchase a mobile number of your choice to use for sending messages through your Twilio account:

trail account twilio

Get the number of your choice, copy your account SID and token. Go over to Auth0 and add it to your SMS config and save:

sms twilio

Create the Auth component

Create a new file called Auth.js. This file will host all our code implementations for this project. I’m doing this to keep everything in one place and maintain orderliness in my explanations:

import React, {Component} from 'react';
import Auth0 from 'react-native-auth0';
import {Button, View, TextInput, Modal, Text, Image} from 'react-native';
class Auth extends Component {
  constructor() {
    super();
    this.state = {
      phone: '',
      code: '',
      codeRequestSent: false,
      LogginIn: false,
      isLoggedin: false,
      accessToken: '',
      idToken: '',
    };
    this.loginUser = this.loginUser.bind(this);
    this.getLoginCode = this.getLoginCode.bind(this);
  }
  componentDidMount() {
    this.auth0 = new Auth0({
      domain: 'YOUR_AUTH0_DOMAIN',
      clientId: 'YOUR_CLIENT_ID',
    });
  }
  render(){
    return(
      <View></View>
    )
  }
}
export default Auth;

What we’ve done here is create a new instance of the client to make it available in our application. We did this in the componentDidMount() lifecycle method by initializing Auth0 and with your domain and clientID on your Auth0 dashboard. We also declared some state variables to track the values that we’ll need access to all through the app.

Before we go further, let’s refresh again on the passwordless flow we will implement in this project:

  • The user opens the app
  • The app requests the user’s phone number
  • The user provides a phone number
  • App sends a login code to the user’s phone number
  • The user provides the login code to the app
  • The app logs the user in and returns their access and id tokens based on the specified scopes

We will need two functions to implement this flow:

  • getLoginCode() — To send the login code to the user’s phone
  • loginUser() — To use the received code and log the user in:
getLoginCode() {
  this.setState({LogginIn: true});
  this.auth0.auth
    .passwordlessWithSMS({
      phoneNumber: this.state.phone,
    })
    .then(() => {
      this.setState({codeRequestSent: true});
    })
    .catch(console.error);
}

When the user enters their phone number on the app, we store it in the phone state variable and with it, we can request a login code using the above function. Finally, to complete the authentication, send back the received code to Auth0 like so:

loginUser() {
  this.auth0.auth
    .loginWithSMS({
      phoneNumber: this.state.phone,
      code: this.state.code,
    })
    .then(response => {
      console.log(response);
      this.setState({
        accessToken: response.accessToken,
        idToken: response.idToken,
        isLoggedin: true,
      });
    })
    .catch(console.error);
}

When the login request is successful, you can create this user’s record and perform any other user profile related functions you’ve designed for your app.

In the components render() function we display the individual screens conditionally based on the values of the variables we are tracking in state:

render() {
  const {
    codeRequestSent, LogginIn, code, isLoggedin, accessToken, idToken,
  } = this.state;
  return (
    <View>
      {!codeRequestSent ? (
        <>
          <TextInput
            placeholder="Enter Phone"
            onChangeText={text => this.setState({phone: text})}
          />
          <Button
            title={LogginIn ? 'Processing...' : 'Get Code'}
            onPress={this.getLoginCode}
          />
        </>
      ) : (
        <>
          <TextInput
            placeholder="Enter Code"
            value={code}
            onChangeText={text => this.setState({code: text})}
          />
          <Button title="Login" onPress={this.loginUser} />
          <View>
            <Modal transparent={true} visible={isLoggedin}>
              <View>
                <View>
                  <Text> Login Successful 👍🏼🎉</Text>
                  <Text> Here are your details:</Text>
                  <Text> Access Token: {' ' + accessToken}</Text>
                  <Text>
                    Id Token:
                    {' ' + idToken.length > 25
                      ? `${idToken.substring(0, 25)}...`
                      : idToken}
                  </Text>
                  <Button title="Logout" onPress={this.logout} />
                </View>
              </View>
            </Modal>
          </View>
        </>
      )}
    </View>
  );
}

Let’s not forget that this is also the case for email passwordless login. Maybe we’ll cover that flow in detail on the next post. But generally, it’s the same flow — the user gets an email with a link or code depending on your specifications and also uses it to log in.

final product passwordless

Conclusion

In this post, we’ve gone over the concepts involved in implementing passwordless authentication with Auth0 and Twilio in a React Native application. It gave us the opportunity to explore the possibilities of having a secured authentication system without all the hassles that come from dealing with passwords. The possibilities are endless and I can’t wait to see what you build with it. The source code is available on this repository.

Plug: , a DVR for 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.

.
Peter Ekene Eze Learn, Apply, Share

One Reply to “Implementing secure passwordless authentication in React Native apps with…”

  1. Thanks Peter, great reading! I would like to use it for my app but with 2 steps verification- the user will enter his email >> validate the email on our DB >> send verification code to the user phone number (stored on the DB). What will be the best practice?

Leave a Reply