A month of React Native: part #4
This post is part of a series, where I document my experiences learning React Native while building my first-ever mobile app. This is also my way of giving back to the React Native community, with tips and insights I note along the journey.
Most apps have a simple signup/login functionality, which is what we’ll be building in this part of the series. There are many options when it comes to what authentication service one can use, from Identity-as-a-Service (IaaS) products such as Auth0, Firebase, Okta, AWS Cognito to spinning up your own identity management system. For this example, we’ll be using AWS Cognito.
We’ll have two screens that an unauthenticated user sees: the
Signup screen and the
Login screen. Let’s bundle these two screens together in a layout that we’ll call
Authenticated layout will only be shown when the user has correctly authenticated with Cognito and it will show the list of items we built in part 3. We’ll just add a
Logout button that will clear the user’s authenticated session and return us to the
Unauthenticated layout. Pretty simple, right? Let’s do this.
A little background
Before continuing, I will assume that you’ve followed the chapter on Creating a Cognito User Pool and Creating a Cognito Identity Pool from the excellent Serverless Stack tutorial. What’s the different between a “User Pool” and an “Identity Pool” you ask? Make sure you read the explanation here.
Once you’re done setting up your User Pool and Identity Pool, let’s save the following configuration parameters in a config file:
Oh, and before we continue — make sure you’ve installed the AWS Amplify library. This makes interacting with Cognito (and other AWS services) really easy:
Setting up the routing
As we said earlier, we’ll need to switch between the two top-level layouts,
Authenticated. Let’s split out this in a separate file, following the example in the Serverless Stack tutorial.
One thing to note here that’s new: the
createSwitchNavigator method is used to ensure we show only one screen/layout at a time. This is exactly what we want to ensure we only show authenticated screens when the user is signed in. The
react-navigation documentation on this has more details. Aside of this, everything else should be familiar, from what we did back in part #2.
Login with AWS Cognito
Let’s implement the
Login screen, including calling the AWS Cognito service for authentication. Here’s what the code for this screen looks like:
Assuming we’ve already created a test user, this should work as expected. We also included a navigation link to the
Signup screen, where users without an active account can sign up. The code for this looks very similar to
Login, so I’ll omit it.
But there is a small problem: we don’t get to see the
Authenticated layout after we successfully logged in. Remember that the SwitchNavigator uses the isAuthenticated flag to choose whether to display the
Authenticated or the
Unauthenticated layout. Yes, we could cheat and navigate directly to the
Authenticated layout after a successful login, but this ad-hoc navigation can become messy really fast. What we really want is the top-level app container to drive this functionality using internal state. And we also want that the children of the app container modifying this state (with a callback) whenever the auth state changes (i.e. login or logout). This sounds like a job for the new and shiny React Context. This is exactly what we’re going to use!
Saving auth state
Since we haven’t showed what the top-level app container looks like yet, let’s see the “before” shot. Trust me — it’ll get a lot sexier really soon ;)
I’m not going to go into details on how React Context works, but instead I’ll lay out what functionality we need here.
- Our top-level app container needs to maintain a piece of state on whether the current user is authenticated or not. This will drive the
RootNavigatorto show the correct layout, based on the authenticated state.
- Any child that performs an authentication-related function (e.g.
Signout) needs to be able to update the authenticated state using a callback.
Let’s deal with these one at a time. First, we’ll add some state in our top-level app container that we’ll use to drive
RootNavigator. As you’ll see, this won’t do exactly what we want for now, but it’s a start.
What did we add here? First, we added a boolean
isAuthenticated in the state that tracks whether the current user is authenticated (duh!). Second, we also added a call to
currentSession from the Amplify library. This attempts to renew a previous authenticated session, without us writing any code. Sweet!
Now let’s hook up Context so that the
Login component can update this state. We’ll add all Context-related code in a separate file, as shown below. This may look familiar (or not), but I’ll explain what we did here step-by-step.
Next, we’ll use the
AuthContext in the app container. The only thing we need to do is wrap
AppContainer with the context provider, as shown here (we only show the
render method for brevity):
setAuthenticated method is simply a setter for
Final step: using the context in the
Login component. Here is where we’ll use the
withAuthContext HOC that we haven’t discussed yet. This is a really easy way to use the context consumer in any component we want to. Here is what the
handleSubmit method in the
Login component looks like now:
We also need to export the component using the
OK. Pause. Breathe.
What did we just do? Using React Context, we are able to get access to the top-level app container’s
setAuthenticated method, which is available as a prop. Calling this with
true as the parameter, this will set
isAuthenticated to true, which will in turn trigger the
SwitchNavigator to display the
Authenticated layout. Boom! Here it is in action:
Two things need to happen when the user hits the “Logout” button: (a) call the corresponding method in Amplify to clear the active session on the back-end and (b) update the
isAuthenticated flag in our state. Luckily, we have all the tools we need to do both. Here’s what the
Home screen looks now:
Just like the
Login example above, setting the
true after a successful
SwitchNavigator takes care of redirecting us to the
Unauthenticated layout. Done and done.
A note on AWS Amplify
There is an even simpler way of doing this, if you plan to use AWS Cognito as your IaaS provider. The documentation has a lot more details, but in short, you can simply let the AWS Amplify library do almost all of the above for you, showing all the required screens (including 2FA screens, etc).
I opted in doing this more manually here, since this is way more flexible and with minimal changes can be adapted to your IaaS provider of choice. Just as one of my favorite YouTube chefs calls it, this is more of a “techniques” post rather than a “recipe” post.
Wow, this was a long one. Hopefully it was also pretty useful. Thanks for sticking with me! Next up, we’ll look into some cool things from the Expo toolset, such as getting location information. See you there!
If you enjoyed this article, feel free to hit that clap button 👏 to help others find it.
I’m Alex, a software engineer and startup geek. Currently, I’m a co-founder at a startup called AgentRisk, where I’m the VP of Product & Engineering. In a past life, I was part of the founding engineering team at an enterprise cloud storage startup in Silicon Valley, did a bunch of cool cutting-edge projects at Cisco Research, and worked on some really innovative data center network architectures while doing my Master’s at UCSD. I always enjoy learning new technologies and b̵u̵i̵l̵d̵i̵n̵g̵ shipping side-projects all the time.