The Complete React Native Guide to User Authentication with the Amplify Framework
Tags: aws, reactnative, serverless, expo
Published: 2019-12-02 14:33:16

---
title: The Complete React Native Guide to User Authentication with the Amplify Framework
published: true
description: An in depth guide for adding authentication to your next mobile app using React Native and AWS Amplify
tags: aws, react native, serverless, expo
cover_image: https://thepracticaldev.s3.amazonaws.com/i/q3udj5gmdvnfb5kepf2e.jpg
---

In my previous post, [The Complete Guide to User Authentication with the Amplify Framework](https://dev.to/dabit3/the-complete-guide-to-user-authentication-with-the-amplify-framework-2inh), I walked through how to add username / password based authentication as well as OAuth with Facebook, Google or Amazon.

In this tutorial, I will be covering mobile authentication using React Native and AWS Amplify. This guide will cover both React Native and Expo. I will cover how to implement the following use cases:

1. OAuth with Google & Facebook
2. OAuth with Apple
3. Hosted UI (Google + Apple + Facebook + Username & Password in one UI)
4. Username & password authentication
5. Protected routes
6. Listening to authentication events
7. Basic authentication with the `withAuthenticator` HOC

---

## Getting Started

AWS Amplify provides Authentication APIs and building blocks for developers who want to create apps with real-world production-ready user authentication.

With Amplify you can incorporate username / password based authentication as well as OAuth with Facebook, Google, Amazon, or any third party OAuth provider such as Auth0 or Okta via OIDC.

![OAuth Buttons](https://thepracticaldev.s3.amazonaws.com/i/jeiymr983sv4zaamck05.jpg)

We also provide a pre-built “Hosted UI” that provides a full OAuth + username / password flow with a single function call.

![Hosted UI](https://thepracticaldev.s3.amazonaws.com/i/fmoa9rmn5wwqwk0il3es.jpg)
### Introduction to Amazon Cognito

The Amplify Framework uses [Amazon Cognito](https://aws.amazon.com/cognito/) as the main authentication provider. Amazon Cognito User is a managed user directory service that handles user registration, authentication, account recovery & other operations.

Amplify interfaces with Cognito to store user data, including federation with other OpenID providers like Facebook, and Google.

The Amplify CLI automates the access control policies for these AWS resources as well as provides fine grained access controls via GraphQL for protecting data in your APIs.

Most modern applications require multiple authentication options, i.e. Facebook login + Username / password login. Amazon Cognito makes this process easy by allowing you to use a single user registry to authenticate users across multiple authentication types.

In this post, you'll learn how to add authentication to your application using both OAuth as well as username & password login.

## OAuth with Apple, Google, & Facebook


### Installing the Amplify CLI

To build authentication into your application with Amplify you first need to install the AWS Amplify CLI. The Amplify CLI is a command line tool that allows you to create & deploy various AWS services.

To install the CLI, we'll run the following command:

```sh
$ npm install -g @aws-amplify/cli
```

Next, we'll configure the CLI with a user from our AWS account:

```sh
$ amplify configure
```

> For a video walkthrough of the process of configuring the CLI, click [here](https://www.youtube.com/watch?v=fWbM5DLh25U).

### Creating the React Native project

Next, we'll create the React Native application we'll be working with.

### If using Expo

```sh
$ npx expo init rnamplify

> Choose a template: blank

$ cd rnamplify

$ npm install aws-amplify aws-amplify-react-native
```

### If using the React Native CLI

```sh
$ npx react-native init rnamplify

$ cd rnamplify

$ npm install aws-amplify aws-amplify-react-native amazon-cognito-identity-js

$ cd ios

$ pod install --repo-update

$ cd ..
```

### Creating the Amplify project

Now we can now initialize a new Amplify project from within the root of our React Native application:

```sh
$ amplify init
```

Here we'll be guided through a series of steps:

- Enter a name for the project: __amplifyauth__ (or your preferred project name)
- Enter a name for the environment: __local__ (or your preferred environment name)
- Choose your default editor: __Visual Studio Code__ (or your text editor)
- Choose the type of app that you're building: __javascript__
- What javascript framework are you using: __react-native__
- Source Directory Path: __/__
- Distribution Directory Path: __build__
- Build Command: __npm run-script build__
- Start Command: __npm run-script start__
- Do you want to use an AWS profile? __Y__
- Please choose the profile you want to use: __YOUR_USER_PROFILE__

Now, our Amplify project has been created & we can move on to the next steps.

## Creating our App IDs

In our app we'll be having four types of authentication:

- Facebook (OAuth)
- Google (OAuth)
- Apple (OAuth)
- Cognito (username + password)

Next we'll need to create Apple, Facebook, & Google Apps in order to get an App ID & App Secret for each of them. For each provider that you'd like to enable, create App IDs by following the following instructions.

To see instructions for the __[Facebook](https://developers.facebook.com)__ setup click [here](https://aws-amplify.github.io/docs/js/cognito-hosted-ui-federated-identity#facebook-instructions).

To see instructions for the __[Google](https://console.developers.google.com/apis/credentials)__ setup click [here](https://aws-amplify.github.io/docs/js/cognito-hosted-ui-federated-identity#google-sign-in-instructions).

To see instructions for the __[Apple](https://developer.apple.com/account)__ setup see the tutorial [here](https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple#create-an-app-id). You only need to create the __App ID__, the __Services ID__, and the __Private Key__. You do not need to create a Client Secret. For the Services ID web domain and Return URL, leave it blank for now.

After you've created the Apple, Facebook, & Google OAuth credentials move on to the next step.

## Creating & configuring the authentication service

Now that our Amplify project has been initialized & we have our App IDs & secrets from Apple, Facebook & Google we can add the authentication service.

As of this blog post, the Amplify CLI has not yet added support for Apple so we will need to do that in a separate step by enabling Apple directly in the dashboard. For now, we will only enable Google and Facebook from the CLI.

To add the authentication service, we can run the following command:

```sh
$ amplify add auth

# If you already have a project configured & want to now add Social login, run amplify update auth instead
```

This will walk you through a series of steps:

- Do you want to use the default authentication and security configuration? __Default configuration with Social Provider (Federation)__
- How do you want users to be able to sign in when using your Cognito User Pool? __Username__
- What attributes are required for signing up? __Email__
- What domain name prefix you want us to create for you? __amplifyauthXXXXXXXXX__ (use default or create custom prefix)
- Enter your redirect signin URI: If you are using Expo: __exp://127.0.0.1:19000/--/__, if you are using the React Native CLI: __myapp://__ (this can be updated later for production environments)
- Do you want to add another redirect signin URI: __N__
- Enter your redirect signout URI: If you are using Expo: __exp://127.0.0.1:19000/--/__, if you are using the React Native CLI: __myapp://__ 
- Do you want to add another redirect signout URI: __N__
- Select the social providers you want to configure for your user pool: Choose __Facebook__ & __Google__

> In the above step we chose _Default configuration with Social Provider (Federation)_. This will allow a combination of Username / Password signin with OAuth. If you only want Username / Password, you could choose _Default configuration_ or _Manual Configuration_.

We also set the `redirect` URI. This is important and we will be updating the Expo or Xcode and Android Studio projects later on with this URI.

Finally, you'll be prompted for your App IDs & Secrets for both Facebook & Google, enter them & press enter to continue.

Now that the authentication service has successfully been configured, we can deploy the service by running the following command:

```sh
$ amplify push
```

After running `amplify push` you should see a success message & the __OAuth Endpoint__ should also be logged out to the console:

![OAuth endpoint](https://thepracticaldev.s3.amazonaws.com/i/mwtmnrmzt0534n01m02a.png)

The OAuth endpoint should look something like this:

```sh
https://amplifyauth8e79c995-8e79c995-local.auth.eu-central-1.amazoncognito.com/
```

This OAuth endpoint is also available for reference in __src/aws-exports.js__ if you need it at any point under the `oauth` -> `domain` key.

You will need to use this endpoint to finish configuring your Apple, Facebook, & Google OAuth providers.

### Configuring Facebook

Next, open the Facebook app we created earlier & click on __Basic__ in the left hand menu.

![](https://thepracticaldev.s3.amazonaws.com/i/lhnv5cmhie9wpkbpg1jv.png)

Scroll to the book & click Add Platform, then choose Website:

![](https://thepracticaldev.s3.amazonaws.com/i/ql7oyizcxizminti0mle.png)

For the _Site URL), input the OAuth Endpoint URL with `/oauth2/idpresponse` appended into Site URL:

![](https://thepracticaldev.s3.amazonaws.com/i/thj18ote374ct839m7lw.png)

Save changes.

Next, type your OAuth Endpoint into App Domains:

![](https://thepracticaldev.s3.amazonaws.com/i/oonjcdz1534yxos5rt5i.png)

Save changes.

Next, from the navigation bar choose __Products__ and then __Set up from Facebook Login__ & choose __Web__. 

For the __Valid OAuth Redirect URIs__ use the OAuth Endpoint + `/oauth2/idpresponse`. If you're prompted for the site URL, also use this endpoint (i.e. https://amplifyauth8e79c995-8e79c995-local.auth.eu-central-1.amazoncognito.com/oauth2/idpresponse):

![Valid OAuth Redirect URIs](https://thepracticaldev.s3.amazonaws.com/i/l160rh516fye3ajrsn8h.png)

Save changes.

Make sure your app is _Live_ by clicking the __On__ switch at the top of the page.

![](https://thepracticaldev.s3.amazonaws.com/i/a3glwfwhbo1gijtf83k2.png)

### Configuring Google

Now that Facebook has been configured we can now configure Google. To do so, let's go to the [Google Developer Console](https://console.developers.google.com/apis/credentials) & update our OAuth client.

Click on the client ID to update the settings.

Under __Authorized JavaScript origins__, add the OAuth Endpoint.

For the __Authorized redirect URIs__, add the OAuth Endpoint with `/oauth2/idpresponse` appended to the URL:

![](https://thepracticaldev.s3.amazonaws.com/i/u0wdz5dxteg27upjaqsx.png)

Save changes.

### Configuring Apple

Open the [Apple developer console](https://developer.apple.com/account), click on __Certificates, IDs, & Profiles__ in the left hand menu, then click on __Identifiers__.

In the __App IDs__ dropdown menu, choose __Service IDs__.

![Service IDs](https://thepracticaldev.s3.amazonaws.com/i/l280b08nq63sfs6ji9e9.png)

Click on the __Service ID__ you created earlier, then click __Configure__ next to __Sign In with Apple__.

![Configuring Apple Sign In](https://thepracticaldev.s3.amazonaws.com/i/3kroypaxojie99hemafv.png)

Here, enter the __Domain__ and __Return URLs__. The Domain should be the `oauth` domain value located in the __aws-exports.js__ file. The __Return URL__ will be a variation of the `domain` that will look like this:

```sh
https://<domain>/oauth2/idpresponse
```

So, your return url could look something like:

```sh
https://rnauth6508c5d5-6508c5d5-dev.auth.us-east-1.amazoncognito.com/oauth2/idpresponse
```

![Configuring redirect and domain](https://thepracticaldev.s3.amazonaws.com/i/arvn4cl1ruu64d1wv8nz.png)

> __NOTE__ You do not have to verify the domain because the verification is only required for a transaction method that Amazon Cognito does not use.

## Adding Apple Sign In to the Cognito Service

The Amplify CLI integrated the Google and Facebook OAuth services with Amazon Cognito, but to enable Sign In with Apple we must go into the console and do it manually until the Amplify CLI adds this feature. To open the Cognito project, run the following command:

```sh
$ amplify console auth

?  Which console: User Pool
```

In the left hand menu, choose __Identity Providers__. In this section, click on __Sign in with Apple__ and enter the Apple Services ID, the Team ID, the Key ID, and upload the Private Key given to you from the Apple Developer Console.

![Cognito - Sign in with Apple](https://thepracticaldev.s3.amazonaws.com/i/7zxtfav3n3dgiem6ajw4.png)

Next, click on __App client settings__ and enable __Sign in with Apple__ for each app client.

![Cognito App client settings](https://thepracticaldev.s3.amazonaws.com/i/5jbtlo2gn9tkrc6wst4h.png)

Finally, click on __Attribute mapping__ and be sure to enable __email__ and map it to _email_.

![Cognito Attribute mapping](https://thepracticaldev.s3.amazonaws.com/i/ns5q9wcvh6q81cferxjf.png)

## Configuring local redirect URIs

In the amplify configuration step we set redirect URIs for the app to open back up after the user has been authenticated. Now, we need to enable these redirect URIs on our mobile project. These steps will differ depending on whether you are building with Expo or with the React Native CLI.

### Expo - redirect URIs

If you are using expo, open the __app.json__ file and add the following key value pair to the "expo" property:

```
{
  "expo": {
   "scheme": "myapp",
   // other values
  }
}
``` 

### React Native CLI - redirect URIs

If you're using the React Native CLI and working with the native projects, you will need to configure both the Xcode project as well as the Android Studio project.

#### iOS - Xcode configuration

For iOS, open the Xcode project (in the __ios__ folder, __rnamplify.xcworkspace__). Here, open `info.plist` as source code, and add the following:

```xml
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  <dict>
</array>
```

For a full example, click [here](https://gist.github.com/dabit3/6313925a278872b2adf5d399fefa6e71#file-info-plist-L24).

### Android - Android Studio configuration

In Android Studio, open __android/app/main/AndroidManifest.xml__. In this file, add the following _intent-filter_:

```xml
<intent-filter android:label="filter_react_native">
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="myapp" />
</intent-filter>
```

For a full example, click [here](https://gist.github.com/dabit3/d4ba2104b204ec5fb7489c26590c0da5#file-androidmanifest-xml-L21).

## Trying it out

Now, the project and the services are configured and we can start writing some JavaScript.

The first thing we need to do is configure the React Native Project to use the Amplify credentials. To do so, open __index.js__ and add the following code:

```javascript
import Amplify from 'aws-amplify'
import config from './aws-exports'
Amplify.configure(config)
```

Now, we can test out the authentication APIs. To do so, we will be using the `Auth.federatedSignIn` methods. These methods allow us to launch either Federated Sign In with a single provider, or launch the Hosted UI for signing in with any provider.

```javascript
// import the Auth class
import { Auth } from 'aws-amplify'

<Button
  title="Sign in with Google"
  onPress={() => Auth.federatedSignIn({ provider: "Google" })}
/>
<Button
  title="Sign in with Facebook"
  onPress={() => Auth.federatedSignIn({ provider: "Facebook" })}
/>
<Button
  title="Sign in with Apple"
  onPress={() => Auth.federatedSignIn({ provider: "SignInWithApple" })}
/>
<Button
  title="Launch Hosted UI"
  onPress={() => Auth.federatedSignIn()}
/>
```

Next, run the app to test everything out:

```sh
# If using Expo

$ expo start

# If not using Expo

$ npx react-native run-ios

# or

$ npx react-native run-android
```

After signing in, we can test out a couple of other things.

To log out the current user's credentials:

```javascript
const user = await Auth.currentAuthenticatedUser().catch(err => console.log(err))
```

Using the above method, we can also check if the current user is signed in at any time. If they are not signed in, the error message will tell us that no user is signed in.

If they are signed in, the `user` object will be populated with all of the metadata of the signed in user.

To sign out the current user:

```javascript
await Auth.signOut()
```

## Username + Password authentication

With our current setup, we can also sign up and sign out users with a username and password.

To do so, we need to capture their info in a form. Using the `Auth` class, we can handle many difference scenarios, including but not limited to:

- Signing up
- Confirming sign up (MFA)
- Signing in
- Confirming sign in (MFA)
- Resetting password

Let's take a look how to sign a user up. This is a very basic example that does not take into account switching form state between sign up, sign in, and confirming sign up or sign in. A more detailed example is linked below.

```javascript
// import the Auth component
import { Auth } from 'aws-amplify'

// store the form state
state = {
  username: '', email: '', password: ''
}

// sign the user up
async signUp = () => {
  const { username, email, password } = this.state
  await Auth.signUp({ username, password, attributes: { email }})
  console.log('user successfully signed up')
}
```

To view all of the methods available on the `Auth` class, check out the documentation [here](https://aws-amplify.github.io/amplify-js/api/classes/authclass.html).

If you're interested in how to create a custom authentication flow, check out the components in [this](https://github.com/aws-samples/aws-amplify-auth-starters/tree/react-native/src/nav/auth) example, or just check out the entire React Native Authentication Starter [here](https://github.com/aws-samples/aws-amplify-auth-starters/tree/react-native).

## Protected / Private Routes

When creating a custom authentication flow, the one thing you need to deal with is protected or private routes.

Protected routes are routes or views that you do not want accessible to certain users. In our example, we will implement protected routes to redirect users who are not signed in and allow users who are signed in to proceed.

The example I will show is assuming you are using React Navigation, but if you are using a different navigation library the idea will still be the same.

Essentially what you need to do is have a listener for a route change, or if you are using React Navigation you can hook directly into the route change using the `onNavigationStateChange` prop.

In this function, we can get the user's credentials and check if the user is signed in. If they are signed in, we allow then to continue to the next route.

If they are not signed in, we redirect them to the Authentication screen:

```javascript
import React from 'react'
import { createSwitchNavigator, createAppContainer, NavigationActions } from 'react-navigation'

import Auth from './nav/auth/Auth'
import MainNav from './nav/main/MainNav'

import { Auth as AmplifyAuth } from 'aws-amplify'

const SwitchNav = createSwitchNavigator({
  Auth: {
    screen: Auth
  },
  MainNav: {
    screen: MainNav
  }
})

const Nav = createAppContainer(SwitchNav)

class App extends React.Component {
  checkAuth = async () => {
    try {
      await AmplifyAuth.currentAuthenticatedUser()
    } catch (err) {
      this.navigator.dispatch(
        NavigationActions.navigate({ routeName: 'Auth' })
      )
    }
  }
  render() {
    return (
      <Nav
        ref={nav => this.navigator = nav}
        onNavigationStateChange={this.checkAuth}
      />
    )
  }
}

export default App
```

For a complete implementation, check out the example project [here](https://github.com/aws-samples/aws-amplify-auth-starters/tree/react-native).

## Listening to authentication events

There is a listener we can initialize that will listen to changes in our authentication state and allow us to have access to the type of authentication event that happened and update the application state based on that data.

With Amplify, the `Hub` module allows us to do this pretty easily:

```javascript
import { Hub } from 'aws-amplify';

Hub.listen('auth', (data) => {
  const { payload } = data;
  console.log('A new auth event has happened: ', data.payload.data.username + ' has ' + data.payload.event);
})
```

## Basic authentication with the `withAuthenticator` HOC

If you're just looking to get up and running with basic username + password authentication, you can use the `withAuthenticator` HOC.

This component will put authentication in front of _any_ component in your app with just a couple of lines of code:

```javascript
import { withAuthenticator } from "aws-amplify-react-native";

class App extends React.Component { /* your code /* }

export default withAuthenticator(App)
```