Building an Authentication Flow with React Navigation

Updated: March 27, 2017

I’m asked fairly often about setting up an authentication flow with React Navigation. That’s what we’ll cover today — we’ll have two “layouts” a signed in layout with a TabNavigator and a signed out layout with a two screen StackNavigator.

I’ll be using React Native Elements to handle the UI for this app.

Prefer video? Get the rundown in this 5 minute clip.

Overview

Our app is going to work like so…

When the user first opens the app we’ll show them the SignedOut layout where they can then log in (logging in will simply consist of pressing the login button, everything else will just be for looks). When logged in the SignedIn layout should replace the SignedOut layout. A user shouldn't be able to swipe or go back to the previous layout unless they log out.

If a user previously logged in then we should show them the SignedInlayout immediately when they come back to the app.

Upon logging out the SignedOut layout should then be visible again. Again, a user shouldn't be able to go back to the SignedIn layout unless they sign in.

Following Along

If you want to follow along, or check out the finalized code, you can do so by checking out the project on GitHub. To get started all the screens will be set up already and we’ll focus solely on the routing logic.

Approach

Thinking about the app overview we know we need two “layouts”. The SignedOut layout can be represented by a StackNavigator. The SignedIn layout will be represented by a TabNavigator (you could easily use a DrawerNavigator instead).

We also need a way to determine which initial layout is shown — we’ll handle that in the primary entry point of the app (app/index.js). To keep track of whether the user has previously signed in or not will be accomplished with AsyncStorage. When logging in we'll set a key to notate that.

Finally we need a root SwitchNavigator that we’ll use to change primary layouts.

Setting up the SignedOut Layout

First we’ll set up our SignedOut layout. In app/router.js create a new StackNavigator with the SignIn and SignUp screens.

You’ll also want to use this SignedOut component in the app entry point.

Finally, update SignUp.js to, when pressing the "Sign In" button, navigate to the Sign In screen.

That should leave with something like this

Setting Up the SignedIn Layout

Now let’s set up the TabNavigator for the SignedIn layout.

Then render that from the entry point

Leaving with the the following

Tracking Sign In State

Now that we’ve got our different layouts put together let’s first handle our login logic, which takes place in app/auth.js. This is purely for demonstration's sake - obviously you would want to hook into a real auth system in reality.

For the onSignIn and onSignOut functions I'm either writing to or removing from AsyncStorage. In the isSignedIn function I'm returning a promise and in that promise I check for the existence of the "USER_KEY" - if it exists (meaning we're logged in) I resolve true from the promise, otherwise I resolve false.

I created these abstractions to keep all of our login logic in one place.

We can then update the app/index.js to call and use this information in determining which layout to render.

In the componentDidMount I make a call to the isSignedIn function to check whether this user was previously logged in and then update the component state with that information. I also tell my component that we've checked and have gotten a response back from that function.

I then use the component state in my render method to determine what should be rendered. If we’re still waiting for a response from the function I render null so there aren’t any flashes of the wrong layout. The rest is self explanatory.

Since our Sign Up/In and Sign Out buttons are already calling the onSignInand onSignUp functions we can test this out. When pressing the button you won't notice anything but if you refresh the app you'll notice the new layout rendered.

Configuring the Root Navigator

We’re going to create a new SwitchNavigator for our root. However, we’re going to create a function that actually returns the new root navigator and we can change the initial route depending on the signed in state.

You can see that my different “layouts” are the screens of this navigator . The big difference is that I’ve wrapped this in a function and I determine the initial route by the signedIn argument of the function.

I can then call it from my app entry point like so.

This will give the exact same experience as we had before, just using a navigator.

Now if I update the call to onSignIn in SignIn.js or SignUp.js to, upon resolving the promise returned, navigate to the SignedIn layout I get the following interaction.

The code for that looks like this

Likewise we can do the opposite for Profile.js

One thing I want to note about this approach is that you’ve got to be intentional and very aware of an re-renders in the file you call the createRootNavigator because whenever it's called your nav state will be lost.

How are you handling the authentication flow when using React Navigation?

Curious about my strategies for other common tasks in React Native? Checkout any one of my many React Native courses!