Authorization and Authentication with AWS Cognito and React Native

Zakariya Ahmed
Slalom Build
Published in
10 min readJan 28, 2022

Authorization and Authentication are often the biggest hurdles for new applications, proof-of-concepts, and MVPs. Security concepts can be challenging for developers to comprehend and are often prioritized below business needs. Nevertheless, implementing a sound authorization and authentication solution is critical for an application’s success.

This guide will cover how to implement security for a mobile React Native application utilizing AWS Cognito. The source code for this application can be found here.

If you want to run this application on your personal mobile device, download Expo Go from the App Store which will help us test on iPhone or Android.

Before diving in, let’s review the differences between Authentication and Authorization:

Authentication: The act of validating that users are who they claim to be. This is usually the first step in the security process. Abbreviated as AuthN.

Authorization: The process of giving a user permission to access specific resources or services. Abbreviated as AuthZ.

In secure production-level environments, authorization should follow authentication. Users must first prove their identities before being granted the requested access.

React Native Authentication With AWS Cognito

This section covers how to set up AWS Cognito User and Identity Pools for use in a mobile application. At a high level, a pool essentially acts as a user directory. Let’s review the differences between User and Identity pools:

User Pool: Utilized for authentication or identity verification. Allows application users to sign in or federate with a third-party identity provider (IdP).

Identity Pool: Utilized for authorization or access control. Used to create unique identities for users which grant access to other AWS services, such as AWS S3.

Creating a User Pool with Amazon Cognito

The first step is opening the Amazon Cognito service in your AWS account. Hit “Manage User Pools” and then “Create a User Pool” in the top right hand corner.

Give the user pool a name and select “Review defaults”.

Now we have access to multiple settings for the user pool. For this example, we will be utilizing email as the Required attributes. The settings also allow us to set the user’s password length and decide the password policy, which determines which characters a password should contain.

Before creating the pool, we will need to select “Add app client”.

On the next page, select “Add an app client”.

Unselect “Generate client secret” and populate App client name with a name of your choosing.

For those curious, client secrets are used by applications with server-side components for another layer of security.

Click “Create App Client”.

On the next page, select “Return to pool details”.

Then press “Create Pool” to complete this step.

Make note of your Pool ID and App Client ID, you will need those in the next step.

Congratulations! You’ve just created your first Cognito User Pool. Next, let’s create a Federated Identity.

Create a Federated Identity

Now it is time to set up Federated Identity Pools to authorize users and grant them access to the services and features they need to utilize.

AWS Federated Identity allows us to create unique identities for our users and federate them with our identity provider. In this example, the user pool we created in the last step is acting as the identity provider (IdP).

Let’s set up the federated identity. This can be done after creating the user pool by selecting “Federated Identities” in the top left hand corner.

Decide on a name for the Identity Pool and populate the “Identity pool name*” field.

Under “Authentication Providers” enter the Pool ID from the previous step for User Pool ID and the App Client Id from the user pool.

After selecting “Create Pool” AWS will generate IAM roles to use with the identity pool.

Press “Allow” to continue.

Before moving onto the React Native application, be sure to make note of the User Pool Id, User Pool App Client Id, and Identity Pool Id.

AWS Cognito is now ready to be integrated with our mobile application!

React Native Integration

With AWS Cognito configured, it is time to build the React Native application and integrate our security solution. Feel free to download the source code here.

Create the React Native Mobile Application

Let’s take a look at what is in this repository at a high level:

/screens

This directory holds the UI screens for our app. There are 5 screens in this example for the user to sign up and log in.

/navigation

This directory holds the navigation implementation for the application. This example is using stack navigator, which provides a way for the app to transition between screens.

/store

This directory manages the global state for our application using Redux. For this application, we want to persist a user name and security token.

App.js

This file orchestrates the navigation and state of the application. AWS Amplify will also be configured in this file using aws-exports.js.

aws-exports.js

This file contains the credentials required to connect to the AWS Cognito User Pool we created earlier. For an even more secure solution, consider passing the credentials in as variables during runtime.

Configure App to Utilize Cognito User Pools

To connect our application with our Cognito User and Identity pools, we will leverage the AWS Amplify library, which helps the application communicate with AWS services. Update the aws-exports.js file with your credentials:

const awsmobile = {
aws_project_region: '<AWS_REGION>',
aws_cognito_identity_pool_id: '<IDENTITY_POOL_ID>',
aws_cognito_region: '<AWS_REGION>',
aws_user_pools_id: '<USER_POOL_ID>',
aws_user_pools_web_client_id: '<APP_CLIENT_ID>',
oauth: {},
};
export default awsmobile;

Test the integration

Run the following commands to test if the integration works:

$npm install
$npm start

This will start a local development server. A web browser should appear with a QR code.

Use a mobile device to scan the QR code which will open the application using Expo Go from the App Store.

On startup, users will be directed to the Login screen. To register a new user, click “Sign Up” and follow the on screen prompts. When we set up our User Pool, the default password requirements were:

  • 8 characters
  • 1 Upper case letter
  • 1 Special character
  • 1 Number

If the user does not pass these minimum requirements, AWS Cognito will send us an InvalidParameterException error code back.

The UI blocks the user from submitting an invalid password and displays an error letting the user know they did not meet the minimum requirements.

Click “Next” with a valid password and AWS Cognito will send a verification code to the email account used.

At this point, our user should now exist in the Cognito User Pool as an unconfirmed account. You can verify this by navigating to the Cognito User Pool in the AWS console and clicking on Users and groups under General Settings.

Now, navigate to the email account associated with the app account and retrieve the the confirmation code.

If we go back to the Cognito User Pool once the code is submitted, we will see our user is now CONFIRMED. With this, we can attempt to log in to our application!

Attempt to login with your new user. Open the app again and enter the email and password you previously used to sign up. On success, the terminal will print out the response from AWS Cognito for us to take a look at:

CognitoUser {
"Session": null,
"attributes": Object {
"email": "zakariya.ahmed@slalom.com",
"email_verified": true,
"name": "Zak",
"sub": "952d34dc-a3df-4258-8f23-091c6dedea97",
},
"signInUserSession": CognitoUserSession {
"accessToken": CognitoAccessToken {
"jwtToken": "eyJr...",
"payload": Object {
"token_use": "access",
"username": "zakariya.ahmed@slalom.com",
},
},
"idToken": CognitoIdToken {
"jwtToken": "eyJr...",
},
},
"username": "zakariya.ahmed@slalom.com",
}

We can see Cognito is able to authenticate this user as legitimate. To verify further, try logging in with an email account that is not in the user pool — Cognito will return a NotAuthorizedException.

We now have a working login page that authenticates a user against the Cognito User Pool. Next, let’s look at how we can use the JWT token returned from Cognito in our API calls.

Signing API Calls

The idtoken.jwtToken sent back to the application from AWS Cognito allows us to call our backend APIs and services securely for our user. If your application is utilizing API Gateway for backend services and AWS Cognito has been set as the API’s authorizer, adding the token to the header of the API calls is as simple as:

async someRESTRequest(jwtToken) {
try {
const response = await fetch(`<YOUR_API_URL>`, {
method: "GET",
headers: {
Authorization:
"Bearer " + jwtToken /*the JWT token from AWS Cognito. */,
},
});
const responseData = await response.json();
if (response && !response.ok) {
let err = new Error("HTTP status code: " + response.status);
err.response = response;
err.status = response.status;
throw err;
}
return responseData;
} catch (err) {
console.log("There was an error getting activity types.");
console.log("Err: " + JSON.stringify(err));
throw err;
}
}

With AWS Cognito, you can easily lock your APIs down to only the users that are authenticated and authorized to access the application resources.

Use Cases for AWS Cognito

Hopefully by now we are getting comfortable with implementing a security solution for authenticating and authorizing mobile application users. Setting up Cognito User and Identity Pools can be done in around 10 minutes, and AWS Amplify makes it easy for mobile applications to communicate with AWS Cognito. When thinking about security solutions, here are some scenarios where AWS Cognito might be the the right choice:

1. Setting up prototype applications or Proof of Concepts

AWS Cognito is a great choice for POCs or prototypes when developers or businesses are focused on proving the functionality of the application and want a quick and easy authorization and authentication solution to spin up.

2. Delegating Password Security

Persisting user passwords and ensuring they are secure is a big responsibility and risk for an organization to take on. Fortunately with AWS Cognito, Amazon assumes this responsibility for you. Developers and organizations do not have access to the user passwords stored in Cognito, which is excellent from a security standpoint. Additionally, AWS Cognito meets compliance standards, such as HIPAA.

3. Simple Integration with AWS Cloud Services

AWS Cognito integrates seamlessly with Amazon API Gateway, allowing you to secure your endpoints from the AWS console. Using Federated Identities, mobile application users can interact with services such as AWS S3, Lambda, and DynamoDB in a secure fashion. Federated Identities also allows mobile applications to only grant users access to what they are allowed to see without compromising the rest of the application’s data.

Potential AWS Cognito Challenges

Now that we know AWS Cognito is easy to set up for web and mobile applications, let’s explore potential challenges. Here are some points to keep in mind when picking AWS Cognito as your service provider:

1. AWS Disaster Recovery Limitations with Cognito

An AWS outage occurred in November 2020 that crippled AWS Cognito for a period of time. During the outage, any application using AWS Cognito could not authenticate users or validate sessions. On top of this, AWS Cognito does not currently support regional fallback options. If you are planning on using AWS Cognito for a production-level application, consider creating a disaster recovery plan for if and when this situation arises again.

2. Limited Configuration Capabilities

There are a myriad of non-adjustable quotas for AWS Cognito defined in the documentation. Some of these quotas you might never have to worry about, but other configurations, such as Access Token validity, have a hard cap and are unchangeable. If you want an application that can host user sessions over the course of multiple days, these non-adjustable quotas could hurt your application down the line if you are not careful. AWS Cognito also caps the number of emails it can send per account per day at 50, so for larger applications you would need to integrate Amazon SES if you want to sign users up with email.

3. Some User Pool Configurations Cannot Be Adjusted After Creation

Some AWS Cognito configurations are immutable once you set up the pool. Take for example the sign-in method.

If the pool is initially set up to only support email and the business later decides they also want to support phone numbers for sign in, you would not be able to update the existing Cognito User Pool. At this point, AWS recommends setting up a second User Pool for phone number support. If the application is already in production, you are now stuck with supporting two AWS Cognito User Pools. This is not an ideal situation since it adds complexity to managing your security solution — having two pools means a divergence could happen if both pools aren’t updated in the same way or at the same time, giving users different experiences based on which pool they were added to.

Conclusions and Next Steps

Congratulations! You’ve successfully set up an AWS Cognito security solution for a mobile application and learned how to overcome one of app development’s biggest hurdles: authentication and authorization. You also learned about the use cases for AWS Cognito and some considerations for determining if this cloud solution is right for your business needs.

If you found this guide helpful or have questions about cloud security solutions, please drop a comment!

--

--

Zakariya Ahmed
Slalom Build

Talking to myself because I am my own consultant.