Building an Authentication Flow with React Navigation
Updated: March 27, 2017
I’ve put together an updated version of this article as part of React Native School.
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.
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 SignedIn
layout 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 onSignIn
and 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!