How to implement world 2 factor authentication (both email and TOTP) using React, React Router, and Amazon Cognito
To view Part 2, implementing React Router & TOTP, click here.
In this post, we’ll walk through how to implement real world user sign up and sign in with two factor authentication along with a routing and an authentication flow in a React web application.
When the user is logged out, we will protect certain routes from being accessed and redirect them to sign in, and allow access these protected routes only when a user is signed in. We also want to check on route change whether the user is still currently signed in, and if not redirect them to the sign in / sign up route.
The tools we will be using are Create React App, Glamor for styling, React Router for routing, Amazon Cognito for authentication, and AWS Amplify for interacting with AWS services.
This is part 1 of a 2 part series and follows a similar post I did on React Native Authentication that was very well received.
Part 1 will show how to set up the authentication provider and methods that will interact with our provider, signing up and signing in a user.
Part 2 will go into how to add React Router and implement a real world authentication flow, including protected routes, signing out, TOTP, and more.
The first thing we will do is create our new project, install our dependencies, and set up the Authentication provider.
First, let’s go ahead and create our React project using Create React App, and change into the new project’s directory:
create-react-app react-authcd react-auth
Next, let’s install React Router and Glamor using either npm or yarn:
yarn add react-router-dom glamor
or
npm i react-router-dom glamor --save
You can use any identity provider you would like, but we will be using Amazon Cognito along with the AWS Amplify JavaScript library and the AWS Amplify CLI to autogenerate the resources for us from the command line.
If not already installed, go ahead and install the AWS Amplify CLI:
npm i -g @aws-amplify/cli
Next configure the CLI with AWS IAM credentials:
amplify configure
Click here for a video walkthrough of how to create credentials and configure the CLI
Now, we’ll create a new project (choose the default for all options, or choose a name for your project if you would like)
amplify init
# Here you can choose your text editor of choice & the default for all other options.
This creates a new Amplify project, as well as an aws-exports.js
file in the src directory.
Next we’ll add authentication (Amazon Cognito) and deploy the new configuration:
amplify add auth# choose Y when asked if we would like to use the default configuration
amplify push
amplify add auth
will enable Amazon Cognito in our project with default settings, including 2 factor authentication on signup with email (we will add TOTP later).
Let’s go ahead and add basic user sign up form to our app to see if we can go ahead and sign up a user.
We will be working with the Auth class from AWS Amplify to interact with Amazon Cognito. Auth has quite a few different methods allowing everything from user sign up & sign in to changing and retrieving passwords and everything in between.
The main methods that we will be using are the following:
signUp — signs up a new user
signUp(username: string, password: string, attributes?: object)
confirmSignUp — submits 2 factor authentication for new user sign up
confirmSignUp(username: string, authenticationCode: string)
signIn — signs in an existing user
signIn(username: string, password: string)
Now, let’s wire this up!
The first thing we need to do is configure AWS Amplify at the root of our project, src/index.js
:
We will begin implementing authorization by allowing users to sign up.
Let’s create a new component called SignUp.js
, & place it in the src directory. Here, we will create a basic form that allows users to sign up:
Next, let’s add some state:
We’ve added the items we need to create a user and allow two factor authentication. We will need to also create inputs that will allow us to capture the user information as well as the authorization code. When the user signs up using the signUp method, they will receive an authorization code via email, and will need to input this value into the form and we will then confirm that this code is correct by calling confirmSignUp:
Let’s now create the inputs, buttons, and the onChange
method that will record the input into our state:
Now we’ve created our UI, and we now only need to do one thing: call the Auth methods to sign up and confirm our user, so let’s add these within a couple of class methods now:
Finally, we’ll import and use this component in App.js:
Now, let’s try this out. You should be able to sign up, get an email with the authorization code, then input the code, and get a confirmation in your console when the user is created.
Where is this user data now? We can see this in our console. To check this out, go to Amazon Cognito dashboard, click on “Manage your User Pools”, and then choose the name of your application, and click “Users and Settings”. There, you can view a list of users that have signed up for your app.
Now, we can sign the user in!
The sign in process is very similar to sign up. We capture the user’s username and password and call Auth.signIn(username, password)
, which will sign the user in if successful:
signIn() {Auth.signIn(this.state.username, this.state.password).then(user => console.log('user:', user)).catch(err => console.log('error signing in! :', err))}
This code works, but we will continue by implementing proper user sign in in part 2 when we add routes to our app, but feel free to try it out and see if you can get it working before you see my implementation in Part 2.
If we wanted to access the user data in the above response, we could get it from user.signInUserSession.idToken.payload
which would look like this:
There are multiple ways of getting this data though at any time once the user is logged in, including Auth.currentAuthenticatedUser()
. For the full Auth API, click here.
Once the user is logged in, their session is persisted in localStorage
by Amplify until they call the Auth.signOut
method. So the user can leave the page, come back, and still be logged in!
In part two, we will continue by adding routing and styling as well as TOTP so you can work with Google Authenticator or your TOTP provider of choice vs SMS!
My Name is Nader Dabit . I am a Developer Advocate at AWS Mobile working with projects like AppSync and Amplify, and the founder of React Native Training.
Currently I’m specializing in GraphQL with AWS AppSync as well as authentication & authorization for JavaScript applications, so if this interests you follow me for more future info & tutorials!
If you enjoyed this article, please clap n number of times and share it! Thanks for your time.