Setting up API authentication with AWS Amplify for React Native

Tanner West
React Native Rocket
7 min readJun 2, 2022
Photo by Florian Berger on Unsplash

AWS Amplify makes it easy to get up and running with user authentication for a React Native app, letting users create accounts and sign in to use your app and get access to your APIs. You can use their built-in components or write your own custom ones, which I wrote about in a previous post.

Things can get a little more tricky when you want to add multiple authentication methods to your app and its backend APIs. In this article, I’ll show you how to do just that. We’ll cover these use cases:

  • A “news style app” where only signed-in admins can create, update, and delete content, but any non-authenticated user can read
  • A “social media style app” where only signed in users can create and read posts, and only a post’s owner can update or delete it

Getting Started

In this tutorial, I’ll be using React Native Rocket’s Launch Pad project. This project is set up with the essential user authentication components (sign up, sign in, etc.) and create, update, and read components. In this post, we’ll be provisioning the Amplify resources and implementing the code we’ll need for the create, read and update API operations.

If this is your first time using AWS Amplify, be sure to read the docs on installing the CLI.

To get started, run amplify init from the base directory of the project. The default values should be fine. Once you confirm your configuration choices, the cli will provision the base resources in the AWS cloud.

Once your project is initialized, you’re ready to add Cognito authentication to your app to allow users to create accounts and sign in. Cognito is the service that allows users to sign up and sign in to your app. To do this, run amplify add auth from the project’s root directory. Go ahead and make these selections when prompted:

Do you want to use the default authentication and security configuration? Default configuration
How do you want users to be able to sign in? Email
Do you want to configure advanced settings? No, I am done.

Now you’re ready to provision the needed AWS resources with amplify push . This will create a user pool in the API cloud to manage your app’s users.

Once the resources have been created, you’re ready to create a user in the new user pool. The starter project is already set up to do this. Just head over to the sign up modal and enter a valid email address and a password. You’ll then be emailed a confirmation code, which you can enter in the confirm signup modal. After that, you should be able to log in with your new user.

The frontend code that handles all this is very simple. This is how we log a user in, for example.

import {Auth} from 'aws-amplify';const authSignIn = async (email: string, password: string) => {
try {
await Auth.signIn({username: email, password});
} catch (e) {
setSigninError('Incorrect username or password');
}
};

Check out my other article on implementing auth modals for more details.

Adding an API

Now that you have your Cognito user pool set up and a user created, you’re ready to add an API. In your root project directory, run amplify add api . We’ll be using a GraphQL API in this example, so go ahead and choose these options (you can name the API and key anything you want):

? Please select from one of the below mentioned services: GraphQL
? Provide API name: rnrocketauthlaunchpad
? Choose the default authorization type for the API Amazon Cognito User Pool
? Do you want to configure advanced settings for the GraphQL API Yes, I want to make some additional changes.
? Configure additional auth types? Yes
? Choose the additional authorization types you want to configure for the API API key
? Enter a description for the API key: rnrocketauthlaunchpad
? After how many days from now the API key should expire (1-365): 90
? Enable conflict detection? No
? Do you have an annotated GraphQL schema? No
? Choose a schema template: Single object with fields (e.g., “Todo” with ID, name, description)
? Do you want to edit the schema now? Yes

It’s important that you choose Cognito user pool as your default auth type and API key as your “additional” auth type. If you do it the other way around, this won’t work.

The CLI should have created a schema template for you at amplify/backend/projectname/schema.graphql that looks like this:

type Todo @model {
id: ID!
name: String!
description: String
}

The exclamation marks after the field type mean the field is required. Note that this schema.graphql file is the source of truth for your API endpoints and corresponding database tables. Whenever you make changes to this file and run amplify push , those changes will made in the AWS cloud.

Let’s update the schema to this:

type Post @model {
id: ID!
title: String!
content: String!
}

Go ahead and run amplify push now to provision your API resources. Be sure to answer yes to Do you want to generate code for your newly created GraphQL API and choose the default responses to the rest of the questions.

One huge advantage of using Amplify to build APIs is that its CLI will generate code for you to use to query your API. Once the CLI is done with the push operation, you should now see a new graphql folder in src that contains files with the code. Open src/api/create.ts , src/api/delete.ts , and src/App.tsx and uncomment the code there to start using the autogenerated queries.

Now we have everything we need to to create and delete posts from our app UI. Go ahead and try it out.

The data you create using your API is stored in a DynamoDB table in the AWS cloud. Log in to your AWS account and navigate to DynamoDB to browse the table contents.

This is very cool, but because the default authentication method for our API is Cognito User Pools, only logged-in users can create, read, update, and delete posts. What if we want to give users permission to view posts without logging in? That’s just what we’ll do in the next section.

Adding “news app style” authentication

First let’s add “news app style” authentication where anyone using the app can read posts, without logging in, but only logged-in users can create, update, and delete posts.

To configure authentication for our endpoint, we add an @Auth directive to our schema with authorization rules that define who can perform what actions on our data. Let’s update our schema like so:

type Post 
@model
@auth(rules: [{allow: private}, {allow: public, operations: [read]}])
{
id: ID!
title: String!
content: String!
}

This will allow logged-in Cognito users to perform any operation on our API data, while non-authenticated users can only read the data. Even though the rule says “public,” the API will still require a valid API key to be used to read data. Our app will add this key to requests automatically.

There is one last thing we need to do before our API is ready to use. Since Cognito user pools is our default auth method, every API request will use it unless we specify otherwise. In App.tsx add import { GRAPHQL_AUTH_MODE } from ‘@aws-amplify/auth’ and pass the authMode option to our listPosts query like this:

API.graphql(
{query: queries.listPosts, authMode: GRAPHQL_AUTH_MODE.API_KEY}
)

Now you’re ready to run amplify push to make these changes to our backend. Once the changes are live, reload the app and notice how logged-out users can see the list of posts, but only logged-in users can create new ones!

One drawback of using API key authentication is that the keys do eventually expire (we set an expiration date of 90 days, but you can make it up to 365 days), and you have to renew the keys manually. The Amplify docs recommend using IAM Authentication for authenticated users without logging in, and I plan on covering that in a future post.

Adding “social media style” authentication

Now let’s look at what I’m calling “social media style” authentication, where only logged-in users can create and read posts, and only the owner of each post can update and delete it. For this, let’s update our schema:

type Post
@auth(
rules: [
{allow: owner}
{allow: private, operations: [read]}
]
)
@model {
id: ID!
title: String!
content: String!
}

These rules will grant all permissions (create, read, update, and delete) to the owner (i.e. the creator) of the post and grant read permissions to any logged-in user.

There are a couple of things to take note of here concerning the owner rule. This rule depends on the existence of an owner field in the database record. Records created using the schema from the last example will not include this field since there was no owner rule on the schema when they were created, so you may want to go ahead and delete all exiting data from your database before proceeding. Also note that the create operation is granted in our owner rule here, albeit implicitly. If it were granted on the private rule, the owner field will not be created in our database.

Be sure to remove the line authMode: GRAPHQL_AUTH_MODE.API_KEY from App.tsx that we added in the previous section, since we won’t be using API key authentication here. After you’ve done that and deleted data from the previous example, go ahead and run amplify push to update your database. After the backend has finished updating and you’ve reloaded your app, create a new post. Now, if you have a look in your DynamoDB table at the row you just created, you’ll see an owner field with a value of the unique user ID.

Create a new user in the app and log in. You’ll find that you can’t delete posts created by other users, only ones created by the logged-in user!

Conclusion

That’s all for this post. For more information on the various types of Amplify API authentication, check out the Amplify CLI docs. Stay tuned here and on Twitter for more Amplify related posts, including posts covering additional authentication types. As always, feedback and questions are welcome on Twitter @useRNRocket!

--

--