Samaila Bala I'm a frontend engineer and technical writer.

AWS Amplify and React Native: A tutorial with examples

11 min read 3245

AWS Amplify And React Native: A Tutorial With Examples

Editor’s note: This post was updated on 21 July 2023 to include information about customizing your React Native app’s authentication UI, as well as best practices for securing authentication in your app. 

Authentication helps control user access to critical parts of an application. As such, it is a critical part of virtually all types of software. In this tutorial, we’ll explore how to set up authentication in a mobile application using React Native and AWS Amplify.

We’ll cover the following:

To follow along with this tutorial, you should have:

  • Node ≥ v14.x
  • npm ≥ v6.14.4
  • An AWS account
  • Knowledge of JavaScript and React
  • Knowledge of React Native
  • An Android and/or iOS emulator

What is AWS Amplify?

AWS Amplify is a set of products and tools by Amazon that helps mobile and frontend web developers build and deploy full-stack applications on Amazon Web Services. Notable features of AWS Amplify include:

  • Authentication, ie., sign in, sign up, sign out, social authentication, etc.
  • A data store that enables you to persist data online and offline
  • API (GraphQL and REST) that enables you to access your backend data seamlessly
  • Storage solutions that help you manage private, public, or protected user content
  • Analytics
  • Push notifications that let you send targeted communications to users

Setting up AWS Amplify

In order to use Amplify, you first need to create an AWS Account and install the Amplify CLI. Open a terminal and paste the code below to install the Amplify CLI. Note that the following settings are not project-specific settings. That’s why we install the Amplify CLI globally on our machine:

npm install -g @aws-amplify/cli 

After a successful installation of the Amplify CLI, run the following code to configure the CLI:

amplify configure

This interactive CLI command requires your input in two steps before it successfully completes:

  • Authenticating your AWS account
  • Adding an identity and access management (IAM) user

When creating a user, be sure to create a user with AdministratorAccess to AWS services, such as Amplify, Cognito, and Cloudfront. This is necessary for specifying an AWS region, adding the accessKeyId and the secretAccessKey of the user created, and adding an AWS profile.

Follow the instructions on this page to create the accessKeyId and the secretAccessKey of the user created. Make sure you specify that you want to use these credentials in the CLI when you create them.

The screenshot below shows a summary of the aforementioned steps:

A Summary Of The Configuration Steps

Setting up a React Native app

We use Expo to bootstrap our React Native application. Expo is a framework that helps you develop, build, and, deploy projects that run natively on all your users’ devices.

To get started with Expo, launch a terminal and paste the following code:

npx create-expo-app aws-amplify-authentication-tutorial --no-install

After successful installation, a React Native project called aws-amplify-authentication-tutorial will appear in the directory where the command was executed. To change into the newly created directory, use the following command:

cd aws-amplify-authentication-tutorial

Then, use the following command to install the dependencies declared on the package.json file:

npm install

Adding AWS Amplify to a React Native application

Now that we have a React Native application and the Amplify framework set up, we need to connect Amplify to our React Native application. To do so, run the following command inside your React Native application directory:

amplify init

Running The Amplify Init

You’ll be prompted to specify the following:

  • Name of the project
  • Name of the environment — I’d recommend sticking with the default dev because we are in a development environment (to choose the default option, press enter)
  • Your default editor of choice
  • The type of app you’re building (JavaScript)
  • Source directory path ( ./src )
  • Distribution directory path (./dist)
  • The authentication method you want to use — select the AWS Profile, then select the profile you created earlier

Upon completion of this form, a folder called amplify is created in your applications root directory to store the backend configuration of your application, such as authentication. Additionally, a file called aws-exports.js is created in the source directory path we specified when initializing Amplify. This file contains the information for the services you create with Amplify. Then, the .gitignore file is modified to include files and folders generated by Amplify that shouldn’t be added to your Git repository. Finally, a cloud project is generated in the AWS Amplify Console. You can access it anytime by running amplify console.

Next, we have to install Amplify dependencies, as well as a few Expo-compatible React Native dependencies required to add Amplify to your application. To do this, run the following commands in your terminal:

npm install @aws-amplify/ui-react-native aws-amplify amazon-cognito-identity-js react-native-url-polyfill

// expo compatible dependencies
npx expo install @react-native-async-storage/async-storage @react-native-community/netinfo react-native-get-random-values react-native-safe-area-context

Then, open the App.js file in your code editor and add the following lines of code after the last import statement:

import { Amplify } from 'aws-amplify';
import awsExports from './src/aws-exports';
Amplify.configure(awsExports);

We’ve successfully added Amplify to our React Native project. Run the command npm start to launch the project in your emulator of choice.

Adding Amplify auth to React Native

Amazon Amplify uses Amazon Cognito under the hood to power the authentication process. Amazon Cognito is a service that simplifies the process of adding authentication, including sign up, sign in, sign out, OAuth, multifactor authentication, etc.

To get started, go back to your terminal, and run the following command inside your project root directory:

amplify add auth

On the interactive prompt that shows up after entering the command, choose the default configuration, then choose email as the method with which you want your users to be able to log in:

Option To Choose The Default Config

After initializing the authentication service, run the command below to deploy it:

amplify push

At this point, we can integrate the authentication service into our application. The Amplify framework provides built-in, customizable UI components that are easy to integrate, which helps streamline the process.

Go to your App.js and add the following line below the import statements:

import { withAuthenticator } from '@aws-amplify/ui-react-native';

withAuthenticator is a higher-order component that automatically detects the authentication state of the application and updates the UI. Remove the export default before the App function definition, place it at the bottom of the App.js file, and then wrap the App component with the withAuthenticator component:

export default withAuthenticator(App)

Your App.js file should look similar to this:

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { Amplify } from 'aws-amplify';
import awsExports from './src/aws-exports';
Amplify.configure(awsExports);
import { withAuthenticator } from '@aws-amplify/ui-react-native';

function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
export default withAuthenticator(App);

Save and run the app in your simulator:

npm start

You should see something like this:

 

After the user creates an account, AWS Amplify will automatically send a code to the user’s email to verify their account:

User Email Verification

Adding logout functionality

After successful authentication, the user is taken to the app screen and has no way of logging out:

Successful Logout Screen

To add a sign out button, navigate to the src directory, and create a subdirectory named screens. Inside the screens subdirectory, create a file named Home.js and add the following code to it:

import React from 'react';
import { StyleSheet, Text, View, Pressable, Dimensions } from 'react-native';
import { Auth } from 'aws-amplify';
const { width } = Dimensions.get('window');
const Home = () => {
  const signOut = async () => {
    try {
      await Auth.signOut({ global: true });
    } catch (error) {
      console.log('error signing out: ', error);
    }
  };
  return (
    <View style={styles.container}>
      <View style={styles.header}>
        <Text style={styles.headerText}>Welcome!</Text>
        <Pressable style={styles.button} onPress={() => signOut()}>
          <Text style={styles.buttonText}>Sign out</Text>
        </Pressable>
      </View>
    </View>
  );
};
const styles = StyleSheet.create({
  container: {
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
    width: width,
    paddingVertical: 20,
  },
  header: {
    display: 'flex',
    padding: 20,
    width: width,
    alignItems: 'center',
  },
  headerText: {
    fontSize: 28,
    fontWeight: 'bold',
  },
  button: {
    marginTop: 50,
    backgroundColor: '#B00020',
    padding: 10,
    borderRadius: 6,
  },
  buttonText: {
    color: '#fff',
    fontSize: 18,
  },
});
export default Home;

This creates a Home component that renders a welcome message and a sign out button. When the user clicks the sign out button, it calls the Auth.signOut() method, which is one of the many methods provided by the Auth class of aws-amplify. This method signs the user out.

Open your App.js file and refactor it to include the Home component:

import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import { Amplify } from 'aws-amplify';
import awsExports from './src/aws-exports';
Amplify.configure(awsExports);
import { withAuthenticator } from '@aws-amplify/ui-react-native';
import Home from './src/screens/Home';
function App() {
  return (
    <View style={styles.container}>
      <Home />
      <StatusBar style="auto" />
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
export default withAuthenticator(App);

Your screen should look like this after saving:

Sign Out Button At The Top Right Of The Screen

Click on the Sign out button to sign out and you will be redirected to the sign in page.

Customizing the authentication UI

In this section, we will customize the Authenticator component provided by Amazon Amplify so the authentication UI suits your application’s needs.

First, return to your App.js file and import the Authenticator component in the line where you imported the withAuthenticator component:

import { withAuthenticator, Authenticator } from '@aws-amplify/ui-react-native';

From now on, you will be using the Authenticator component instead of withAuthenticator to add the authentication functionality to your application. Replace the code inside the App function with the following:

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
      >
        <View style={styles.container}>
          <Home />
          <StatusBar style="auto" />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

Now, remove the withAuthenticator component in the line where you are exporting the App component:

export default App;

Reload your application and the sign in page will still show. According to the official Amplify UI docs, the Authenticator component has the following optional slots, which are rendered on each subcomponent:

  • Header: Renders above subcomponent content, no default provided
  • Footer: Renders below subcomponent content, no default provided
  • Container: Wraps the Authenticator. Can be overridden by extending Authenticator

Adding the header

Navigate to the src directory and create a new a subdirectory named layout. Inside the layout subdirectory, create a file named MyAppHeader.js and add the following code to it:

import { Text, View } from 'react-native';
import {
  useTheme,
} from '@aws-amplify/ui-react-native';

const MyAppHeader = () => {
  const {
    tokens: { space, fontSizes },
  } = useTheme();
  return (
    <View>
      <Text
        style={{
          fontSize: fontSizes.xxl,
          paddingBottom: space.xxl,
          textAlign: 'center'
        }}
      >
        My Custom Header
      </Text>
    </View>
  );
};
export default MyAppHeader

The code above creates a custom header that will be shown at the top of your application. Then, go to the App.js file, import the MyAppHeader component and add it to the Header slot located in the Authenticator component:

import MyAppHeader from './src/layout/MyAppHeader';

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        Header={MyAppHeader}
      >
        <View style={styles.container}>
          <Home />
          <StatusBar style="auto" />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

Your application should now look like this:

Header Added To The Application

Whenever you don’t see changes in your app, go to the terminal and press the R key to reload your application.

To create a footer, simply create a file named MyAppFooter.js inside the layout subdirectory and add the following code to it:

import { Text, View } from 'react-native';
import {
  useTheme,
} from '@aws-amplify/ui-react-native';

const MyAppFooter = () => {
  const {
    tokens: { space, fontSizes },
  } = useTheme();
  return (
    <View>
      <Text
        style={{
          fontSize: fontSizes.xxl,
          paddingTop: space.xxl,
          textAlign: 'center'
        }}
      >
        My Custom Footer
      </Text>
    </View>
  );
};
export default MyAppFooter

The code above creates a custom footer that will be shown at the bottom of your application. Then, go to the App.js file, import the MyAppFooter component, and add it to the Footer slot located in Authenticator component:

import MyAppFooter from './src/layout/MyAppFooter';
function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        Header={MyAppHeader}
        Footer={MyAppFooter}
      >
        <View style={styles.container}>
          <Home />
          <StatusBar style="auto" />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

Your application should now look like this:

Footer Added To The Application

Customizing form fields

AWS Amplify allows you to customize the form fields’ contents, labels, and placeholders by simply adding a new formFields prop to your Authenticator component.



Add the following code to your App.js file to edit the signIn page’s username form field:

const formFields = {
  signIn: {
    username: {
      labelHidden: false,
      placeholder: 'Enter your username here',
      isRequired: true,
      label: 'Username:'
    },
  },
}

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        formFields={formFields}
      >
        <View style={styles.container}>
          <Home />
          <StatusBar style="auto" />
        </View>
      </Authenticator>
    </Authenticator.Provider >
  );
}

The code above creates a new object named formFields, which stores the form fields customizations. The customization replaces the username field’s default label and placeholder. Now instead of asking for the email, it will ask for the username.

Finally, the code removes the Header and Footer slots in the Authenticator component, and adds the formFields object as a prop:

App Before And After Customizing Form Field Label And Placeholder

AWS Amplify also allows you to rearrange the order in which the form fields appear. For the sake of this tutorial, let’s assume that you want customize the signUp page and you want the email field to appear at the bottom instead of the top.

To do so, add the following code to the formFields object to reorder the fields in the signUp page:

const formFields = {
  signIn: {
    username: {
      labelHidden: false,
      placeholder: 'Enter your username here',
      isRequired: true,
      label: 'Username:'
    },
  },
  signUp: {      
    email: {     
      order: 3 
    },
    password: {
      order: 1
    },
    confirm_password: {
      order: 2
    },
  }
}

App Comparison After Reordering Form Fields

Styling AWS Auth pages

When it comes to styling the Auth pages provided by AWS Amplify, there are two widely used ways to do it. The first is applying a custom style to the Authenticator component container, and the second is by using a ThemeProvider component.

1. Applying a custom style to the Authenticator component container

To apply a custom style to the container, first import the useTheme Hook to expose the colors constant:

import { withAuthenticator, Authenticator, useTheme } from '@aws-amplify/ui-react-native';

Next, set the container background color to yellow:

function App() {
  const {
    tokens: { colors },
  } = useTheme();
  return (
    <Authenticator.Provider>
      <Authenticator
        Header={MyAppHeader}
        Footer={MyAppFooter}
        Container={(props) => (
          <Authenticator.Container
            {...props}
            style={{
              backgroundColor: colors.yellow[60],
            }}
          />
        )}
      >
        <View style={styles.container}>
          <Home />
          <StatusBar style="auto" />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

Your application should now look like the following:

Applying A Custom Style To The Authenticator Component Container

2. Using a ThemeProvider component

Using a ThemeProvider component allows you to have more control in how the AWS Amplify Auth pages look.

Let’s assume that your application brand color is green and purple and create a custom theme. Create a file named myTheme.js in your project root’s directory and add the following code to it:

import { useTheme } from '@aws-amplify/ui-react-native';
function getTheme() {
  const {
    tokens: { colors },
  } = useTheme();
  const theme = {
    name: 'Custom Theme',
    tokens: {
      colors: {
        background: {
          primary: {
            value: colors.green['100'],
          },
          secondary: {
            value: colors.red['100'],
          },
        },
        font: {
          primary: colors.white,
          secondary: colors.orange['10'],
          interactive: {
            value: colors.orange['80'],
          },
        },
        brand: {
          primary: {
            '10': colors.purple['10'],
            '80': colors.purple['80'],
            '90': colors.purple['90'],
            '100': colors.purple['100'],
          },
        },
      },
    },
  };
  return theme
}

export default getTheme

The code above creates a function named getTheme. Inside this function, it creates a custom theme that changes the background color to green, the primary color to purple, and the font primary and secondary to white and orange, respectively.

Go to the App.js and add the following code to it:

import {
  withAuthenticator, Authenticator, 
  useTheme, ThemeProvider
} from '@aws-amplify/ui-react-native';

import getTheme from './myTheme';

function App() {
  const {
    tokens: { colors },
  } = useTheme();
  const myTheme = getTheme()
  return (
    <ThemeProvider theme={myTheme}>
      <Authenticator.Provider>
        <Authenticator
          formFields={formFields}
        >
          <View style={styles.container}>
            <Home />
            <StatusBar style="auto" />
          </View>
        </Authenticator>
      </Authenticator.Provider>
    </ThemeProvider>
  );
}

Here, the code first imports the ThemeProvider component and the getTheme() function. Next, the code calls the getTheme() function and stores the value returned in a constant named myTheme.

Finally, it wraps ThemeProvider around the Authenticator.Provider, and sets the theme to the custom theme stored in the myTheme constant. Your application should now look like the following:

Using ThemeProvider To Style AWS Amplify Auth pages

Best practices for securing your authentication

When developing a mobile app using AWS Amplify with React Native, you can take advantage of several built-in security measures to enhance the authentication process. Here are some best practices and an overview of these security measures.

User authentication and authorization

AWS Amplify provides multiple authentication options, like username and password, social identity providers (such as Google and Facebook), and federated authentication with services like Amazon Cognito. Choose the most appropriate method based on your app’s requirements. To add an extra layer of security for user logins, implement multi-factor authentication (MFA).

You can also manage permissions for authentication users by using fine-grained access controls and AWS Identity and Access Management (IAM) roles, which will ensure that users can only access resources they are authorized to use.

Secure storage of credentials

Never store sensitive data like API keys, tokens, or passwords directly in your code. Use secure storage mechanisms, such as AWS Secrets Manager, Key Management Service (KMS), or SecureKeychain in React Native, to store sensitive information.

HTTPS and secure communication

Ensure that all communication between the mobile app and backend services occurs over HTTPS. AWS Amplify handles the secure communication by default when interacting with AWS services.

Input validation and sanitization

Implement input validation and sanitization on both the client and server sides to prevent common security vulnerabilities like cross-site scripting (XSS) and SQL injection.

Secure backend APIs

Protect your backend APIs with AWS API Gateway and implement authorization mechanisms, such as API keys or OAuth tokens, to control access to your API resources.

Secure mobile app code

Regularly update dependencies to ensure that your mobile app uses the latest secure libraries and frameworks. Additionally, apply best practices for React Native development to minimize the risk of introducing vulnerabilities into your app.

Logging and monitoring

Implement robust logging in your mobile app and backend services to monitor for suspicious activities and potential security breaches. Use AWS CloudWatch or similar services to monitor your infrastructure and applications for security-related events. Use LogRocket to capture logs and session recordings to detect bugs and better understand user behavior.

Conclusion

In this tutorial, we walked through how to use the AWS Amplify framework to authenticate users in a React Native application. The Amplify framework offers many more features that we didn’t get a chance to cover.

The repository of the application built in this tutorial is available on GitHub. If you have any questions, feel free to drop them in the comments.

LogRocket: Instantly recreate issues in your React Native apps.

LogRocket is a React Native monitoring solution that helps you reproduce issues instantly, prioritize bugs, and understand performance in your React Native apps.

LogRocket also helps you increase conversion rates and product usage by showing you exactly how users are interacting with your app. LogRocket's product analytics features surface the reasons why users don't complete a particular flow or don't adopt a new feature.

Start proactively monitoring your React Native apps — try LogRocket for free.

Samaila Bala I'm a frontend engineer and technical writer.

Leave a Reply