This post will cover:

Overview of production tested Authentication flows.

Implementation of Auth flow using the existing application from Part 1.

Wiring up Redux to handle application UI and some auth state.

Using AWS Amplify to handle Cognito user sessions.

The navigation library we will be using is React Navigation, but these patterns will translate to basically any navigation library.

Auth Flow

Getting the authentication flow right in the beginning of your app development saves an enormous amount of time down the road if it is implemented correctly. The goal of this post is to show you how to set up some basic yet real world authentication end to end, as well as how to wire it into the UI of your application in a way that makes sense in the real world.

Let’s take a quick look at a very common and useful navigation / auth flow.

In Example 1, LoggedInNavContainer and LoggedOutNavContainer are wrapped in a single entry component. These two components could be any types of navigation (drawer, stack, tab), but in our example we will be building, LoggedInNavContainer will be a Stack, and LoggedOutNavContainer will be tabs.

Example 1

In Example 1, we are basically checking a loggedIn boolean (coming from your state management of choice), and rendering an entirely different component based on their logged in state.

These two main components are usually Navigation components in and of themselves.

Of course there are other circumstances to take into consideration, such as “Account Locked”, “Reset Password”, or “Forgot Password”, though we could either add more logic to our if statement with components / UI to handle this, or handle these from within the LoggedOutNavContainer navigator.

Another option is to make the Main entry a Navigator in and of itself, handling the entire auth state and navigating accordingly. Let’s take a look at another approach, and in more detail:

Example 2

In this example, there is a main Navigation component (think Stack Navigator from React Navigation), with a Login / Auth stack (or Login / Auth routes within the same stack), and an “Application” stack that is only accessible / pushed to if the user is logged in.

We will be focusing on the first example as it implements tabs, and is not as easy to reason about in practice as the second set of routes using only StackNavigators.

Getting Started

To start, you should either have followed along with part one and have that project ready to go, or clone this project and configure all of the fields in src/aws-exports.js to match your information from the AWS Console.

You can also create part 1 by following the following screencast:

Next, we need to go ahead and update the main entry entrypoint to show or hide the main app Navigation depending on Authentication state. We want to show the tabs for signing up and signing in when not signed in, and we want to show the main application navigation when we are signed in.

Let’s move App.js into our src directory, and update the file to the following:

Here, we are using the Auth class from Amplify to check it there is a user. If there is a user, we show the Nav component (our main application), if not we show the Tabs component (our sign in / sign up screens).

We are also connecting this component to our redux store because we want it to re-render whenever something changes in our auth state that we will be holding in redux.

Next, we’ll update index.js to import App.js from the correct location and add our soon to be created redux configuration:

import React from 'react'

import { AppRegistry } from 'react-native';

import App from './src/App'; // redux

import { createStore, applyMiddleware } from 'redux'

import { Provider } from 'react-redux'

import rootReducer from './src/reducers'

import thunk from 'redux-thunk'

const store = createStore(rootReducer, applyMiddleware(thunk)) // Amplify

import config from './src/aws-exports'

import Amplify from 'aws-amplify'

Amplify.configure(config); // App

const ReduxApp = () => (

<Provider store={store}>

<App />

</Provider>

) AppRegistry.registerComponent('RNAmplifyExample', () => ReduxApp);

Creating the folder structure

Now, let’s add the rest of the files and folders we will need. In the src directory, create the following folders:

mkdir assets auth nav components reducers

And the following files:

touch actions.js theme.js

In the auth folder, create the following files:

touch auth/SignIn.js auth/SignUp.js auth/Tabs.js

Theme

We will be working with a theme file so that you can configure aspects of the project in one place, such as your primary color, secondary color, and font families, without having to go in and update them throughout the project.

In theme.js , go ahead and set up the following configuration:

const colors = {

primary: '#FF1493',

secondary: '#b9b9b9'

} const fonts = {

hairline: 'Lato-Hairline',

light: 'Lato-Light',

base: 'Lato-Regular',

bold: 'Lato-Bold'

} export {

colors,

fonts

}

Assets

Next, download the assets from this folder into your assets folder.

Fonts

Now that you have downloaded the fonts (part of the assets), we need to link them to the project.

To do this, add the following configuration to your package.json :

"rnpm": {

"assets": [

"./src/assets/fonts"

]

}

Next, we will link these fonts to our project so that we can use them:

react-native link

Build

For the remainder of this tutorial, I will be linking to the files that need to be copied into your project, as this project is quite complex, and embedding them would make this tutorial extremely long! I will though be explaining key parts of each file to go over any functionality that may not be intuitive. If you have any questions, please comment and I will do my best to address any questions asap!

Reusable components

Our application will have a couple of components & styles that we will be reusing. Because we don’t want to rewrite this functionality, we create these in our components folder and reuse them throughout our app.

Go ahead and create a Button.js and Input.js file in your components folder, copying the contents of the linked files.

Redux

Let’s start with our reducer.

In reducers, create the following files:

touch reducers/index.js reducers/auth.js

Update index.js to this root reducer, and auth.js to this main auth reducer that will be handling some of our auth state such as whether or not we are currently authenticating, if there is an error message and what it is, and whether or not we should show certain modals.

We also need to add our actions to actions.js.

Our redux configuration is pretty straight forward, and for API calls we are using thunk for asynchronous actions.

Most of the functionality in our actions is happening around the createUser , confirmUserSignUp , authenticate , and confirmUserLogin functions. These functions are interacting with our Amplify Auth class, calling the signIn, confirmSignIn , signUp , and confirmSignUp methods that we looked at in part 1.

Signing In & Signing Up

In this file, we have a basic Sign In form, with a button that will dispatch an authenticate action to redux, which will then call Auth.signIn , passing in the username and password input into the form.

We also have a modal that is shown only once the user has successfully signed in with username & password, but has not yet authenticated with two factor authentication. Once the user has successfully signed in, we show the modal and allow the user to input their authentication code.

This component is similar to our Sign In component, only we have a couple of extra fields for capturing the users’ phone number and email address. We also have the modal functionality so that when a user creates an account, we verify with two factor authentication, sending the user an sms and confirming their sms, hiding the modal once the user sign up is confirmed.

Here, we pull in the SignIn and SignUp screens, implementing them into our TabNavigator.

Logged In State

Once the user is logged in, the Nav component will be rendered in our App.js file.

Nav is a StackNavigator, with a single Home route for now. The Home route will have a logout button to demonstrate logout functionality.

In the Nav directory, create Nav.js and Home.js, copying the contents of the linked files.

That is all, you should be able to run the project and have a working Auth flow in your project!

Conclusion

This project is still lacking in a few areas, such as if a user did not receive their signUp confirmation code for whatever reason, we do not have a way to call the Amplify resendSignUp method with the existing config (though it would be fairly easy to add).

There are also a few minor changes I would like to make regarding UI.

Overall though, this is the type of flow I have seen in some pretty large projects that are currently in production, and have also implemented this type of flow myself, so this project is a great start if you are looking to build your next app with a real world Authentication flow, with a solid provider like Amazon Cognito!

Images courtesy of Amazon Web Services, Inc