Setting up Auth0 on React Native

Published Dec 20, 2017Last updated Jan 22, 2018
Setting up Auth0 on React Native

Modern web applications require an authentication solution that's flexible enough to go where your users are. Auth0 provides just that. They provide a framework of tools to authenticate your users on mobile and web.

Installation

Once you've installed React Native, create a stock React Native application.

$ create-react-native-app Auth0Example
$ cd Auth0Example

Note: do not use the '-' character in your names. Somthing about it keeps breaking Gradle down below.

Ejecting

If you have a recent version of React Native, you have probably noticed a distinct lack of iOS or Android folders. React Native assumes you will write your app in pure JavaScript. If you have no intention of using an oauth flow, you don't really need it. However, I've never had a client that didn't want Facebook or Google login.

This means that when we need to stray off the neat path, React Native lays out into some serious Evil Dead territory. Beware the trees...

Ejecting is a permanent change to the React Native setup that causes it to spit out an Android and iOS folder with their respective build folders. This means you will need to install Gradle, Maven and Pods.

$ brew install gradle
$ brew install maven
$ gem install cocoapods
$ yarn eject

Screen Shot 2017-12-19 at 2.22.44 PM.png

Create your iOS and Android identifiers and keep them noted. Once the script has run, you should now see Android and iOS folders.

From here, make sure you have adb setup. Adb is the Android command line tool for interacting with an Android device. You can install them using Android Studio. In addition, I recommend installing Genymotion. It includes its own adb tooling. Add the path to those tools to the $PATH in your .bashrc or zshrc.

export PATH=$HOME/bin:/Applications/Genymotion.app/Contents/MacOS/tools:$PATH
export ANDROID_HOME=$HOME/Library/Android/sdk

You will need to start Genymotion and start a vm. Have it running in the background before you run the Android build. The iOS script launches the simulator automatically.

From the top level, we need to reset things and reinstall our module (might not be necessary for you, but I found myself doing a lot of mantra reciting here). Run open three terminals to your project root directory.

1$ rm -rf node_modules
1$ yarn install
1$ yarn start
2$ yarn run ios
3$ yarn run android

Fingers crossed, you should have an iOS and Android emulator running side by side.

initial-rn-export.png

Next, we need to install Auth0. Auth0 has official native modules for both iOS and Android. In this tutorial, I will use the official React Native library: react-native-auth0, to set up authentication.

$ yarn add react-native-auth0
$ react-native link react-native-auth0
$ yarn run ios
$ yarn run android

We run the builds for iOS and Android again because we are now hooking in native code modules.

Now it's time to set up our login process.

Setup

If you haven't already set up an Auth0 account, now's a good time. In the top right hand corner, you will see your accounts manager. Create a new tenant.
new-tenant.png

A tenant represents a federation of clients that share a base of users. Let’s say I wanted to create my own super duper project management hub called “TopCamp.”

The set of users in my SaaS would be a tenant and the clients would be web and mobile respectively. I might even go so far as to have different kinds of web applications for my own back-end teams and customer service vs the main product.

By using Auth0, I can specify different authentication policies for each respective entry to my application.

The important thing here is that each tenant has a canonical domain that is chosen when we create the tenant.

Screen Shot 2017-12-19 at 1.36.52 PM.png

Next, we create our first client. This will be the authentication policy used by our React Native application.

new-client.png

Screen Shot 2017-12-19 at 1.42.14 PM.png

Now that you have a client, go to the settings page where we will get the details necessary to configure out the mobile app.

Screen Shot 2017-12-19 at 1.43.29 PM.png

Now we just need to add a singleton for our instantiated Auth0 instance. Create a file src/lib/auth0.js.


import Auth0 from 'react-native-auth0';

const AUTH0_DOMAIN = 'auth0-login-example.auth0.com';
const CLIENT_ID = 'cZXbmzjn5vnMjZzwxhFc4foDWU1Wq4AA';

const auth0 = new Auth0({
  domain: `${AUTH0_DOMAIN}`,
  clientId: `${CLIENT_ID}` 
});

export {
  auth0,
  AUTH0_DOMAIN,
  CLIENT_ID
};

Getting your Identifiers

iOS and Android have special identifiers they use to denote their packages.

To get your Android bundle identifier, find Android/app/src/main/AndroidManifest.xml and locate package="${BUNDLE_IDENTIFIER}"

manifest.png

Your iOS package name will be the value of the name property at the top level's app.json.

{
  "expo": {
    "sdkVersion": "23.0.0"
  },
  "name": "Auth0Example",
  "displayName": "auth0 login"
}

Next inside your Android/app/src/main/AndroidManifest.xml, you will want to add Android:launchMode="singleTask" to the Activity and add an intent. It should look like this:

<activity
  Android:name=".MainActivity"
  Android:label="@string/app_name"
  Android:launchMode="singleTask"
  Android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
  Android:windowSoftInputMode="adjustResize">
  <intent-filter>
      <action Android:name="Android.intent.action.MAIN" />
      <category Android:name="Android.intent.category.LAUNCHER" />
  </intent-filter>
  <intent-filter>
      <action Android:name="Android.intent.action.VIEW" />
      <category Android:name="Android.intent.category.DEFAULT" />
      <category Android:name="Android.intent.category.BROWSABLE" />
      <data
          Android:host="auth0-login-example.auth0.com"
          Android:pathPrefix="/Android/${applicationId}/callback"
          Android:scheme="${applicationId}" />
  </intent-filter>
</activity>

Note the Android:host=“auth0-login-example.auth0.com”. This would be the Auth0 domain that you selected.

Next, we add to the iOS build. Locate the Appdelegate.m by finding iOS/{PACKAGE_NAME}/AppDelegate.[swift|m] and add the following:

#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];
}

Next, locate Info.plist in the same directory and locate a line of code that looks like this.

<key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>

The PRODUCT_NAME:rfc1034identifier is a unique value we need to use for adding a URL type. Underneath that key string pair, add the following, substituting the identifier value with whatever you have for CFBundleIdentifier.

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleTypeRole</key>
        <string>None</string>
        <key>CFBundleURLName</key>
        <string>auth0</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>
        </array>
    </dict>
</array>

Rerun `yarn run iOS and yarn run Android to load the changes.

Let’s return to the Auth0 client page we were on earlier. Here we need to add in some callback URLs.

For iOS, look back at that line.

<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string>

This evaluates to the callback token you'll use in iOS. So in my case, the package name is com.auth0example, so my callback token is org.reactjs.native.example.Auth0Example.

// iOS
{PRODUCT_BUNDLE_IDENTIFIER}://auth0-login-example.auth0.com/iOS/{PRODUCT_BUNDLE_IDENTIFIER}/callback
// -- example:
org.reactjs.native.example.Auth0Example://auth0-login-example.auth0.com/iOS/org.reactjs.native.example.Auth0Example/callback

//Android

{YOUR_APP_PACKAGE_NAME}://auth0-login-example.auth0.com/Android/{YOUR_APP_PACKAGE_NAME}/callback
// -- example
com.auth0example://auth0-login-example.auth0.com/Android/com.auth0example/callback

Screen Shot 2017-12-19 at 6.03.13 PM.png

With that, we can test the authentication flow from App.js.

import React from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';

import { auth0, AUTH0_DOMAIN } from './src/lib/auth0';
export default class App extends React.Component {
  loginWindow() {
    //Alert.alert('You tapped the button!');
    auth0
      .webAuth
      .authorize({scope: 'openid profile email', audience: `https://${AUTH0_DOMAIN}/userinfo`, useBrowser: true})
      .then(credentials => {
        console.log(credentials)
        Alert.alert('You tapped the button!');
        // Successfully authenticated
        // Store the accessToken
      })
      .catch(error => console.log(error));

  }
  render() {
    return (
      <View style={styles.container}>
        <Text>auth0 login example!!</Text>
        <Text>Changes you make will automatically reload.</Text>
        <Text>Shake your phone to open the developer menu.</Text>
        <Button
          title="login"
          onPress={() => this.loginWindow()}
        />
      
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});


Click on the button and you should see the screen.

Screen Shot 2017-12-20 at 1.51.40 AM.png

And now you have an Auth0 based login!

Discover and read more posts from Peter de Croos
get started