DEV Community

Cover image for Authentication ๐Ÿ” CUSTOM SETUP  /  AWS Amplify + React Native
Server Serverlesskiy
Server Serverlesskiy

Posted on • Updated on

Authentication ๐Ÿ” CUSTOM SETUP / AWS Amplify + React Native

One of the most requested topics among my channel subscribers is authentication and authorization in the React Native application. Therefore, I decided to devote a separate post to this issue, but before we start coding, it is necessary to deal with the definition of Authentication/Authorization.

AWS Amplify

Authentication is a verification of the conformity of the subject and the one he is trying to impersonate using some unique information (fingerprints, iris color, voice, etc.), in the simplest case โ€” with the help of mail and password.

Authorization is the verification and determination of the authority to perform certain actions in accordance with previously performed authentication
At the end of this article, we will make this mobile application:

Flow

Authentication is an integral part of almost any application. Knowing who the user is, the unique identifier of the user, what permissions the user has, and whether they are logged in, allows your application to display the correct views and return the correct data for the current logged in user.

Most applications require mechanisms for registering users, logging in, processing encryption and updating passwords, as well as many other tasks related to identity management. Modern applications often require things like OAUTH (open authentication), MFA (multi-factor authentication) and TOTP (time-based time passwords).

In the past, developers had to manually spin all of these authentication features from scratch. This task alone can take weeks or even months from the development team to do everything right and make it safe. In this article, youโ€™ll learn how to correctly and securely implement authentication in a React Native application using Amazon Cognito with AWS Amplify.

Amazon Cognito is AWSโ€™s fully managed identity service. Cognito provides easy and secure user registration, logon, access control, token updating, and user identity management. Cognito scales to millions of users and also supports logging in with social network providers such as Facebook, Google and Amazon.

Cognito consists of two main parts: user pools and identity pools.

User Pools โ€” User pools provide a secure user directory that stores all of your users and scales to hundreds of millions of users. This is a fully managed service. Like serverless technology, user pools are easy to configure, without having to worry about supporting any infrastructure. User pools are what manage all the users who register and log in to the account, and is the main part that we will focus on in this article.

Identity pools โ€” Identity pools allow you to authorize users who are logged into your application to access various other AWS services. Suppose you want to give a user access to a lambda function so that he can receive data from another API. You can specify this when creating the identity pool. User pools include the fact that Cognito or even Facebook or Google user pools can be the source of these identifiers.

A scenario where an Amazon Cognito user pool and an identity pool are used together.

See the diagram for the general Amazon Cognito script. The goal here is to authenticate your user and then give him access to another AWS service.

Amazon Cognito

  1. At the first stage, the user of your application enters the system through the user pool and receives the tokens of the user pool after successful authentication.

  2. Your application then exchanges user pool tokens for AWS credentials through the identity pool.

  3. Finally, your application user can then use these AWS credentials to access other AWS services such as Amazon S3 or DynamoDB.
    Cognito User Pools allows your application to call various methods for a service to manage all aspects of user authentication, including things like:
    User registration
    User Login
    User Logout
    Change user password
    Reset User Password
    MFA Code Verification
    Amazon Cognito Integration with AWS Amplify

AWS Amplify supports Amazon Cognito in a variety of ways. First of all, you can create and configure Amazon Cognito services directly from the AWS Amplify command-line interface. By creating an authentication service through the CLI, you can call various methods (for example, signUp, signIn and signOut) from a JavaScript application using the Amplify JavaScript client library.

Amplify also has pre-configured user interface components that allow you to build entire authentication flows in just a couple of lines of code for environments such as React, React Native, Vue, and Angular.

You ask how much does it all cost?

Using Amazon Cognito Identity to create a user pool, you pay only for the number of active users per month (MAU). MAUs are users who have performed at least one authentication operation during a calendar month: registration, authorization, token renewal, or password change. Subsequent sessions of active users and inactive users in this calendar month are not paid.

Amazon Cognito Identity - Cost

CODING TIME ๐Ÿ‘จ๐Ÿผโ€๐Ÿ’ป๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป

CODING TIME

PART 1
All the code for this part can be found on Github.

Flow

Step 1

Create a new project โš›๏ธ

react-native init messaga
Enter fullscreen mode Exit fullscreen mode

We start the project ๐Ÿš€
iOS

cd messaga && react-native run-ios
Enter fullscreen mode Exit fullscreen mode

Android

cd messaga && react-native run-android
Enter fullscreen mode Exit fullscreen mode

Step 2

We connect icons๐Ÿ‘พ

Since the icons are used by the AWS Amplify framework, we therefore connect them according to this instruction ๐Ÿ“ƒ.

Check for errors. Add to App.js

import Icon from 'react-native-vector-icons/FontAwesome5'

const App = () => {
  return (
    <>
      <Icon name="comments" size={30} color="#900" />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

Step 3

Register your AWS account

We register according to this instruction ๐Ÿ“ƒ and check all 5 steps according to the video tutorial..
Attention!!! You will need a bank card ๐Ÿ’ณ, where should be more than 1 $ ๐Ÿ’ต
There we look and put the Amplify Command Line Interface (CLI)

Step 4

Initializing AWS Amplify in a React Native Project

Initialize our backend in the root directory of the React Native project.

amplify init
Enter fullscreen mode Exit fullscreen mode

We answer the questions:

amplify init

Next is the initialization of the project. ๐Ÿš€
โ ง Initializing project in the cloudโ€ฆ
Your project has been successfully initialized and connected to the cloud!

Step 5

Connecting Authentication Plugin โ€” Auth ๐Ÿ”

Now that the application is in the cloud, you can add some features, such as allowing users to register with our application and log in.
We connect the authentication plugin.

amplify add auth
Enter fullscreen mode Exit fullscreen mode

Select the default configuration. This adds auth resource configurations locally to your amplify/backend/auth directory.
Select the profile we want to use. default. Enter and how users will log in. Email (write off money for SMS).

Select the profile we want to use. default. Enter and how users will log in. Email (write off money for SMS).

amplify add auth

Successfully added resource yourname locally
Send changes to the cloud ๐Ÿ’ญ

amplify push
Enter fullscreen mode Exit fullscreen mode

โœ” All resources are updated in the cloud

Step 6

Connect AWS Amplify to React Native Projectย โš›๏ธ

Details in this manual ๐Ÿ“ƒ, and briefly and in a straight line like this:

yarn add aws-amplify@1.2.4 @aws-amplify/core@1.2.4 aws-amplify-react-native amazon-cognito-identity-js
Enter fullscreen mode Exit fullscreen mode

After installation, be sure to go to the ios folder and set the pods

cd ios && pod install && cd ..
Enter fullscreen mode Exit fullscreen mode

Step 7

Editing the project structure

Create the /src directory and transfer the App.js file there, renaming it to index.js with this content
Edit import in root /yourname/index.js

- import App from './App'
+ import App from './src'
Enter fullscreen mode Exit fullscreen mode

Step 8

Minimal project configuration and Authenticator module

Amplify.configureโ€Š-โ€Šproject configuration
Authenticatorโ€Š-โ€ŠThe AWS Amplify Authentication Module provides authentication APIs and building blocks for developers who want to create user authentication capabilities.

import React from 'react'
import {StatusBar} from 'react-native'
import Amplify from '@aws-amplify/core'
import {Authenticator} from 'aws-amplify-react-native'
import awsconfig from '../aws-exports'

Amplify.configure({
  ...awsconfig,
  Analytics: {
    disabled: true,
  },
})

const App = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <Authenticator usernameAttributes="email" />
    </>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

Run the simulator

Step 9

Edit Inputs in App.js

const signUpConfig = {
  hideAllDefaults: true,
  signUpFields: [
    {
      label: 'Email',
      key: 'email',
      required: true,
      displayOrder: 1,
      type: 'string',
    },
    {
      label: 'Password',
      key: 'password',
      required: true,
      displayOrder: 2,
      type: 'password',
    },
  ],
}


      <Authenticator
        usernameAttributes="email"
+       signUpConfig={signUpConfig}
      />
Enter fullscreen mode Exit fullscreen mode

Step 10

Change the theme of UI๐Ÿ–Œ

We create an export point for our future components /src/components/index.js with the content

export * from './AmplifyTheme'
Enter fullscreen mode Exit fullscreen mode

and accordingly create the /src/components/AmplifyTheme/index.js file itself with the content

import {StyleSheet} from 'react-native'

export const deepSquidInk = '#152939'
export const linkUnderlayColor = '#FFF'
export const errorIconColor = '#30d0fe'

const AmplifyTheme = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'space-around',
    paddingTop: 20,
    width: '100%',
    backgroundColor: '#FFF',
  },
  section: {
    flex: 1,
    width: '100%',
    padding: 30,
  },
  sectionHeader: {
    width: '100%',
    marginBottom: 32,
  },
  sectionHeaderText: {
    color: deepSquidInk,
    fontSize: 20,
    fontWeight: '500',
  },
  sectionFooter: {
    width: '100%',
    padding: 10,
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginTop: 15,
    marginBottom: 20,
  },
  sectionFooterLink: {
    fontSize: 14,
    color: '#30d0fe',
    alignItems: 'baseline',
    textAlign: 'center',
  },
  navBar: {
    marginTop: 35,
    padding: 15,
    flexDirection: 'row',
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
  navButton: {
    marginLeft: 12,
    borderRadius: 4,
  },
  cell: {
    flex: 1,
    width: '50%',
  },
  errorRow: {
    flexDirection: 'row',
    justifyContent: 'center',
  },
  errorRowText: {
    marginLeft: 10,
  },
  photo: {
    width: '100%',
  },
  album: {
    width: '100%',
  },
  button: {
    backgroundColor: '#30d0fe',
    alignItems: 'center',
    padding: 16,
  },
  buttonDisabled: {
    backgroundColor: '#85E4FF',
    alignItems: 'center',
    padding: 16,
  },
  buttonText: {
    color: '#fff',
    fontSize: 14,
    fontWeight: '600',
  },
  formField: {
    marginBottom: 22,
  },
  input: {
    padding: 16,
    borderWidth: 1,
    borderRadius: 3,
    borderColor: '#C4C4C4',
  },
  inputLabel: {
    marginBottom: 8,
  },
  phoneContainer: {
    display: 'flex',
    flexDirection: 'row',
    alignItems: 'center',
  },
  phoneInput: {
    flex: 2,
    padding: 16,
    borderWidth: 1,
    borderRadius: 3,
    borderColor: '#C4C4C4',
  },
  picker: {
    flex: 1,
    height: 44,
  },
  pickerItem: {
    height: 44,
  },
})

export {AmplifyTheme}
Enter fullscreen mode Exit fullscreen mode

And plug the theme into the Authenticator src/index.js component

+import {AmplifyTheme} from './components'

      <Authenticator
        usernameAttributes="email"
        signUpConfig={signUpConfig}
+       theme={AmplifyTheme}
      />
Enter fullscreen mode Exit fullscreen mode

Step 11

Connecting language support

Add export to /src/components/index.js

export * from './Localei18n'
Enter fullscreen mode Exit fullscreen mode

Create the file /src/components/Localei18n/index.js with the contents

import {NativeModules, Platform} from 'react-native'
import {I18n} from '@aws-amplify/core'

let langRegionLocale = 'en_US'

// If we have an Android phone
if (Platform.OS === 'android') {
  langRegionLocale = NativeModules.I18nManager.localeIdentifier || ''
} else if (Platform.OS === 'ios') {
  langRegionLocale = NativeModules.SettingsManager.settings.AppleLocale || ''
}

const authScreenLabels = {
  en: {
    'Sign Up': 'Create new account',
    'Sign Up Account': 'Create a new account',
  },
  ru: {
    'Sign Up': 'ะกะพะทะดะฐั‚ัŒ ะฐะบะบะฐัƒะฝั‚',
    'Forgot Password': 'ะ—ะฐะฑั‹ะปะธ ะฟะฐั€ะพะปัŒ?',
    'Sign In Account': 'ะ’ะพะนะดะธั‚ะต ะฒ ัะธัั‚ะตะผัƒ',
    'Enter your email': 'ะ’ะฒะตะดะธั‚ะต email',
    'Enter your password': 'ะ’ะฒะตะดะธั‚ะต ะฟะฐั€ะพะปัŒ',
    Password: 'ะŸะฐั€ะพะปัŒ',
    'Sign In': 'ะ’ั…ะพะด',
    'Please Sign In / Sign Up': 'ะ’ะพะนั‚ะธ / ะกะพะทะดะฐั‚ัŒ ะฐะบะบะฐัƒะฝั‚',
    'Sign in to your account': 'ะ’ะพะนะดะธั‚ะต ะฒ ัะฒะพะน ะฐะบะบะฐัƒะฝั‚',
    'Create a new account': 'Cะพะทะดะฐะนั‚ะต ัะฒะพะน ะฐะบะบะฐัƒะฝั‚',
    'Confirm a Code': 'ะŸะพะดั‚ะฒะตั€ะดะธั‚ะต ะบะพะด',
    'Confirm Sign Up': 'ะŸะพะดั‚ะฒะตั€ะดะธั‚ะต ั€ะตะณะธัั‚ั€ะฐั†ะธัŽ',
    'Resend code': 'ะ•ั‰ะต ะพั‚ะฟั€ะฐะฒะธั‚ัŒ ะบะพะด',
    'Back to Sign In': 'ะ’ะตั€ะฝัƒั‚ัŒัั ะบ ะฒั…ะพะดัƒ',
    Confirm: 'ะŸะพะดั‚ะฒะตั€ะดะธั‚ัŒ',
    'Confirmation Code': 'ะšะพะด ะฟะพะดั‚ะฒะตั€ะถะดะตะฝะธั',
    'Sign Out': 'ะ’ั‹ั…ะพะด',
  },
}

// "en_US" -> "en", "es_CL" -> "es", etc
const languageLocale = langRegionLocale.substring(0, 2)
I18n.setLanguage(languageLocale)
I18n.putVocabularies(authScreenLabels)

const Localei18n = () => null

export { Localei18n }
Enter fullscreen mode Exit fullscreen mode

And we connect the Localei18n component in src/index.js

import {
   AmplifyTheme,
+  Localei18n
} from './components'
Enter fullscreen mode Exit fullscreen mode
+ <Localei18n />
    <Authenticator
      usernameAttributes="email"
      signUpConfig={signUpConfig}
      theme={AmplifyTheme}
    />
Enter fullscreen mode Exit fullscreen mode

Part 1 done โœ…

PART 2

All the code for this part can be found on Github.

flow

Firstly, in the official documentation Amplify says:

Data is stored unencrypted when using standard storage adapters (localStorage in the browser and AsyncStorage on React Native). Amplify gives you the option to use your own storage object to persist data. With this, you could write a thin wrapper around libraries like:
react-native-keychain
react-native-secure-storage
Expoโ€™s secure store

that the data is stored in an unencrypted form, and this is a risk ๐Ÿ•ท information security with possible negative consequences ๐Ÿ•ธ.

Secondly, the standard UI from Amplify does not always satisfy the UX coming from the customer, so we will solve these two problems in this part.

๐Ÿ‘‰๐ŸปTo be continued

Top comments (6)

Collapse
 
nihp profile image
nihp • Edited

I am using the aws-amplify-react-native package and imported all screens from there. How can I customise the error message in that imported screen.

Collapse
 
serverlesskiy profile image
Server Serverlesskiy
Collapse
 
nihp profile image
nihp

Any option to customize this from aws-amplify-react-native package itself. For eg) In sign In if I not filled password it shows the error as "Custom auth lambda trigger is not configured for the user pool."

How can I change this error message

Thread Thread
 
serverlesskiy profile image
Server Serverlesskiy

Put the code on github and I'll see.

Thread Thread
 
nihp profile image
nihp • Edited

I have found solution to customize the error message github.com/aws-amplify/amplify-js/...

Thanks

Thread Thread
 
nihp profile image
nihp

Can I override the default screen to my custom screen with the same SignIn, SignUp, ConfirmationScreen and Forgot Password screens.

I am using aws-amplify-react-native package.

If I override like this it not reflected as I expected. It shows all the screens in a single screen. How can I add this?

Already I have all the setup except the custom UI. I have used default screens already. But now I need custom screens alone with the already provided functionality in my UI.

Can you suggest any easy way to refactor only the UI screens?