A month of React Native: part #4

Building an authentication flow using AWS Cognito

Alex Loukissas
6 min readJan 14, 2019

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.

Photo by Jose Fontano on Unsplash

Overview

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 Unauthenticated. The 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, Unauthenticated and 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 ;)

Basic app container

I’m not going to go into details on how React Context works, but instead I’ll lay out what functionality we need here.

  1. 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 RootNavigator to show the correct layout, based on the authenticated state.
  2. Any child that performs an authentication-related function (e.g. Login, Signup, or 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.

A slightly sexier app container

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):

Hooking up context to app container

The setAuthenticated method is simply a setter for isAuthenticated.

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 withAuthContext HOC:

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:

Login screen that redirects to Authenticated layout

Logging out

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 isAuthenticated to true after a successful signOut, the 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.

About me

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.

--

--

Alex Loukissas

Engineer. Optimist. Always building side-projects. #LongLA