DEV Community

Nader Dabit
Nader Dabit

Posted on • Updated on

The Complete Guide to User Authentication with the Amplify Framework

The AWS Amplify Authentication modules provide Authentication APIs and building blocks for developers who want to create apps with real-world production-ready user authentication.

With Amplify you can incorporate username / password based authentication as well as OAuth with Facebook, Google or Amazon.

We also provide a pre-built β€œHosted UI” that provides a full OAuth + username / password flow.

This post covers authentication for web applications. For the post on React Native, click here.

Introduction to Amazon Cognito

The Amplify Framework uses Amazon Cognito as the main authentication provider. Amazon Cognito User is a robust user directory service that handles user registration, authentication, account recovery & other operations.

Amplify interfaces with Cognito to store user data, including federation with other OpenID providers like Facebook & Google.

The Amplify CLI automates the access control policies for these AWS resources as well as provides fine grained access controls via GraphQL for protecting data in your APIs.

Most modern applications require multiple authentication options, i.e. Facebook login + Username / password login. Amazon Cognito makes this process easy by allowing you to use a single user registry to authenticate users across multiple authentication types.

In this post, you'll learn how to add authentication to your React application using both OAuth as well as username & password login.

Getting Started

Installing the Amplify CLI

To build authentication into your application with Amplify you first need to install the AWS Amplify CLI. The Amplify CLI is a command line tool that allows you to create & deploy various AWS services.

To install the CLI, we'll run the following command:

npm install -g @aws-amplify/cli

Next, we'll configure the CLI with a user from our AWS account:

amplify configure

For a video walkthrough of the process of configuring the CLI, click here.

Creating the React project

Next, we'll create the React application we'll be working with:

npx create-react-app rn-amplify

cd rn-amplify

Now, we'll install the Amplify library:

npm install aws-amplify

Creating the Amplify project

Now we can now initialize a new Amplify project from within the root of our React application:

amplify init

Here we'll be guided through a series of steps:

  • Enter a name for the project: amplifyauth (or your preferred project name)
  • Enter a name for the environment: local (or your preferred environment name)
  • Choose your default editor: Visual Studio Code (or your text editor)
  • Choose the type of app that you're building: javascript
  • What javascript framework are you using: react
  • Source Directory Path: src
  • Distribution Directory Path: build
  • Build Command: npm run-script build
  • Start Command: npm run-script start
  • Do you want to use an AWS profile? Y
  • Please choose the profile you want to use: YOUR_USER_PROFILE

Now, our Amplify project has been created & we can move on to the next steps.

Creating our App IDs

In our app we'll be having three types of authentication:

  • Facebook (OAuth)
  • Google (OAuth)
  • Cognito (username + password)

Next we'll need to create Facebook & Google Apps in order to get an App ID & App Secret for each of them.

For instructions around the Facebook setup click here.

For instructions around the Google setup click here.

After you've created the Facebook & Google OAuth credentials move on to the next step.

Creating & configuring the authentication service

Now that our Amplify project has been initialized & we have our App IDs & secrets from Facebook & Google we can add the authentication service. To do so, we can run the following command:

amplify add auth

# run amplify update auth if you already have a project configured & want to now add Social login

This will walk us through a series of steps:

  • Do you want to use the default authentication and security configuration? Default configuration with Social Provider (Federation)
  • How do you want users to be able to sign in when using your Cognito User Pool? Username
  • What attributes are required for signing up? Email
  • What domain name prefix you want us to create for you? amplifyauthXXXXXXXXX (use default or create custom prefix)
  • Enter your redirect signin URI: http://localhost:3000/ (this can be updated later for production environments)
  • Do you want to add another redirect signin URI: N
  • Enter your redirect signout URI: http://localhost:3000/ (this can be updated later for production environments)
  • Do you want to add another redirect signout URI: N
  • Select the social providers you want to configure for your user pool: Choose Facebook & Google

In the above step we chose Default configuration with Social Provider (Federation). This will allow a combination of Username / Password signin with OAuth. If you only want Username / Password, you could choose Default configuration or Manual Configuration.

Finally, you'll be prompted for your App IDs & Secrets for both Facebook & Google, enter them & press enter to continue.

Now that the authentication service has successfully been configured, we can create the service by running the following command:

amplify push

After running amplify push you should see a success message & the OAuth Endpoint should also be logged out to the console:

The OAuth endpoint should look something like this:

https://amplifyauth8e79c995-8e79c995-local.auth.eu-central-1.amazoncognito.com/

This OAuth endpoint is also available for reference in src/aws-exports.js if you need it at any point under the oauth -> domain key.

We will need to use this endpoint to finish configuring our Facebook & Google Oauth providers.

Configuring Facebook

Next, open the Facebook app we created earlier & click on Basic in the left hand menu.

Scroll to the book & click Add Platform, then choose Website:

For the _Site URL), input the OAuth Endpoint URL with /oauth2/idpresponse appended into Site URL:

Save changes.

Next, type your OAuth Endpoint into App Domains:

Save changes.

Next, from the navigation bar choose Products and then Set up from Facebook Login & choose Web.

For the Valid OAuth Redirect URIs use the OAuth Endpoint + /oauth2/idpresponse. If you're prompted for the site URL, also use this endpoint (i.e. https://amplifyauth8e79c995-8e79c995-local.auth.eu-central-1.amazoncognito.com/oauth2/idpresponse):

Valid OAuth Redirect URIs

Save changes.

Make sure your app is Live by clicking the On switch at the top of the page.

Configuring Google

Now that Facebook has been configured we can now configure Google. To do so, let's go to the Google Developer Console & update our OAuth client.

Click on the client ID to update the settings.

Under Authorized JavaScript origins, add the OAuth Endpoint.

For the Authorized redirect URIs, add the OAuth Endpoint with /oauth2/idpresponse appended to the URL:

Save changes.

Testing it out

Now, we should have our authentication service set up & ready to go. Let's test it out.

The easiest way to do this will be by using the Auth.federatedSignIn() method from the Auth class from AWS Amplify. This function will render the Hosted UI that will give users the option to sign up & sign in with Facebook, Google, or Username / Password without us having to write any of the code.

To try this out, let's first configure the React application to recognize our Amplify project. We do this by adding the following code below our last import in src/index.js:

// src/index.js

import Amplify from 'aws-amplify'
import config from './aws-exports'
Amplify.configure(config)

Next, open App.js & update the code to the following:

// src/App.js

import React from 'react'
import logo from './logo.svg'
import './App.css'

import { Auth } from 'aws-amplify'

function App(props) {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <button onClick={() => Auth.federatedSignIn()}>Sign In</button>
      </header>
    </div>
  )
}

export default App

Now, run the app:

npm start

Now, when the app launched we should be able to sign in using the Sign In button!

Adding more features

Now that we've added an easy way to sign in, what are the next steps? We will walk through the following:

  1. Learn how to sign out users & check the current signed in user
  2. Adding custom buttons for OAuth providers
  3. How to add custom form for Username / Password sign in with an example
  4. Listening to authentication changes (triggers when an authentication event happens)

How to sign out users & check the current signed in use

Now that we have users signed in, how do we know that they are indeed signed in? We can check for the status of a currently signed in user at any time using the Auth class from Amplify.

Let's update our code to the following so we can add a Sign Out button as well as a button to check the status of the currently signed in user:

// src/App.js

import React from 'react'
import logo from './logo.svg'
import './App.css'

import { Auth } from 'aws-amplify'

function checkUser() {
  Auth.currentAuthenticatedUser()
    .then(user => console.log({ user }))
    .catch(err => console.log(err))
}

function signOut() {
  Auth.signOut()
    .then(data => console.log(data))
    .catch(err => console.log(err))
}

function App(props) {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <button onClick={() => Auth.federatedSignIn()}>Sign In</button>
        <button onClick={checkUser}>Check User</button>
        <button onClick={signOut}>Sign Out</button>
      </header>
    </div>
  )
}

export default App

Now when we run our app we're able to log out information about the currently signed in user as well as sign the user out.

Adding custom buttons for OAuth providers

What if we don't want to use the Hosted UI & want to create our own UI from scratch? We can do this pretty easily. The Auth class also has a few methods that we can use to call OAuth providers directly:

Auth.federatedSignIn({provider: 'Google'})
Auth.federatedSignIn({provider: 'Facebook'})

Let's update our app to have a couple of custom OAuth buttons:

<button
  onClick={() => Auth.federatedSignIn({provider: 'Facebook'})}
>Sign In with Facebook</button>

<button
  onClick={() => Auth.federatedSignIn({provider: 'Google'})}
>Sign In with Google</button>

Now, we have created a custom button for signing in with our OAuth providers.

If you're interested in a live demo of this along with the code, check out amplifyauth.dev & view the code in GitHub here.

Adding a custom form for Username / Password sign in

What if we wanted to also create a custom form for signing in users? We can do that using our existing configuration using the Auth class.

The Auth class has over 30 methods available for managing users for all authentication tasks like signing users up, signing users in, handling MFA, & all of the functionality that goes along with user management in general. (View AuthClass API here).

To get started with a custom form using our existing setup, you can use the following methods to sign users up, confirm sign up (MFA), & sign users in:

// sign user up
Auth.signUp({
  username: someUsername, password: somePassword, attributes: { email: someEmail }
})

// confirm sign up
Auth.confirmSignUp(someUsername, authenticationCode)

// sign user in
Auth.signIn(someUsername, somePassword)

These methods are asynchronous & return promises so you can check to see whether they were successful or not.

To view a custom form using this flow, check out this file.

If you're interested in a live demo of this along with the code, check out amplifyauth.dev & view the code in GitHub here.

You can also check out this repo for end to end examples in different frameworks, complete with protected routes using a custom authentication flow.

Listening to authentication events

Now that we have our users signing in & signing out, what if we want to perform some type of action based on this signed in state? We can listen for all authentication changes easily using the Amplify library.

The class we will be using for this is Hub.

Let's create a listener that listens for all auth events & logs them out:

// src/App.js

// import useEffect hook
import React, { useEffect } from 'react';
import logo from './logo.svg';
import './App.css';

// import Hub
import { Auth, Hub } from 'aws-amplify'

function checkUser() {
  Auth.currentAuthenticatedUser()
    .then(user => console.log({ user }))
    .catch(err => console.log(err));
}

function signOut() {
  Auth.signOut()
    .then(data => console.log(data))
    .catch(err => console.log(err));
}

function App(props) {
  // in useEffect, we create the listener
  useEffect(() => {
    Hub.listen('auth', (data) => {
      const { payload } = data
      console.log('A new auth event has happened: ', data)
       if (payload.event === 'signIn') {
         console.log('a user has signed in!')
       }
       if (payload.event === 'signOut') {
         console.log('a user has signed out!')
       }
    })
  }, [])
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <button onClick={() => Auth.federatedSignIn()}>Sign In</button>
        <button onClick={checkUser}>Check User</button>
        <button onClick={signOut}>Sign Out</button>
        <button onClick={() => Auth.federatedSignIn({provider: 'Facebook'})}>Sign In with Facebook</button>
        <button onClick={() => Auth.federatedSignIn({provider: 'Google'})}>Sign In with Google</button>

      </header>
    </div>
  );
}

export default App

Now whenever a user performs any authentication event, the authentication data will be logged out to the console.

Next Steps

Now that you've added authentication to you app you can begin adding secure backends & APIs to your app with GraphQL or AWS Lamba. To learn more, click here.

If you'd like to host your app using the Amplify Console, click here or check out this video to learn how.

My Name is Nader Dabit. I am a Developer Advocate at Amazon Web Services working with projects like AWS AppSync and AWS Amplify. I specialize in cross-platform & cloud-enabled application development.

Latest comments (55)

Collapse
 
irfanonk profile image
irfan ΓΆnk • Edited

please help it is getting bothering
i have always got invalid_request

here is the question
invali_request

Collapse
 
irfanonk profile image
irfan ΓΆnk

please help it is getting bothering!
i have always got invalid_request:

stackoverflow.com/questions/761288...

Collapse
 
earlpond profile image
EarlPond • Edited

How to: Use my OIDC provider like a Google/Facebook?

(great article)
export default withAuthenticator(App, { federated: {provider: 'myNamefor company SSO provider OIDC' } });

I'm trying to use with Authenticator to wrap a React web app. It feels like I should be able to use the syntax in the article in withAuthenticator as a federated object. Since there will only be one, really no reason to stop on the Hosted UI page. Would like it to continue past the Hosted UI with the one button directly to the Idp.

Think the functionality probably there, I'm just missing the setup & syntax.
docs.amplify.aws/lib/auth/advanced...
The example in Advanced Workflows of the Amplify docs is close, but no mention of tapping into OIDC created providers in Cognito.

========================
I found a good article about being able to bypass directly to the Idp, but I think there may be a better way using withAuthenticator.
spin.atomicobject.com/2021/11/02/b...

Thanks for any insights.

Collapse
 
gvdonovan profile image
Greg Donovan

I'm a bit late to the party but am wondering how signin will work if the user was created by an admin with a temporary password. Will Amplify automatically handle this? If we go the SDK route and roll our own will there be something in the response after signinWithEmail is called indicating we need to capture a new password?

Collapse
 
hoanghai31299 profile image
hoanghai31299

Hi, great post.
Just a question, there is any way to signin with cognito credentials?
In my case, android call the webview (using amplify auth) and send credentials to it.

Collapse
 
nanditareshamwala profile image
NanditaReshamwala

hi Nader,
Great useful article and example.

I have configured SAML IP in my cognito user pool by following the instruction on medium.com/@zippicoder/setup-aws-c...

Next, I need to make my react application to sign in with this SAMl IP. I am using amplify in my react application. How to use Auth.federatedSignIn with SAML provider?

Also, I did not understand the use of following in your example.

"aws_cognito_identity_pool_id": "us-east-2:cec55e7d-2e27-4e4d-800a-8924b3d36eb8",

Collapse
 
dfang profile image
fang duan

hi, how to put sign up link and sign in link in the navbar with hosted ui, when user click sign up, redirect to or show sign up page, when click sign in, redirect to or show sign in page.

@aws-amplify/ui-react

Collapse
 
ttngocthao profile image
Thao Thi Ngoc Truong

How can we add an user to the group of users pool during sign up? For example, buyer, seller and admin group? I’m totally beginner to Aws, It would be great if anyone could please to advise me.?! Thanks

Collapse
 
ca513zn profile image
CarlosZ92

This is an awesome article!

Collapse
 
mersmith profile image
Mersmith

@dabit3
Because there is duplication of users in AWS Cognito

Register a user with name, email and cell phone. After that, log in with Facebook. And I register another user with the same email.

I have two users with the same email.

How do I solve that problem?
AWS AMPLIFY AND COGNITO

Image:
dev-to-uploads.s3.amazonaws.com/i/...

aws #amplify #cognito

dev-to-uploads.s3.amazonaws.com/i/...

Collapse
 
indrajitb profile image
indrajitb

Hey @mersmith

  • Did you find a solution to this problem?
Collapse
 
mersmith profile image
Mersmith • Edited

Register a user with name, email and cell phone. After that, log in with Facebook. And I register another user with the same email.

I have two users with the same email.

How do I solve that problem?
AWS AMPLIFY AND COGNITO

dev-to-uploads.s3.amazonaws.com/i/...

Collapse
 
mersmith profile image
Mersmith

How can we modify the user registration?????
Template UI AWS amplify register.
Video tutorial please.

Collapse
 
josephgoksu profile image
Joseph Goksu

If you get an error for Auth.federatedSignIn({ provider: 'Google' })

try this ⬇️
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth/lib/types";

Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Google
});

Collapse
 
alsmith808 profile image
Alan Smith

Hi Nader,

Thanks for all your Amplify material, really helping me a lot.  Quick question, this could possibly be a problem on my end as I was having an issue with css not loading correctly in another project also.  Anyway I have added Cognito to my local project which I'm mocking, but my Cognito login screen is appearing with no css, have you or anyone come across this problem, the signup has no link so I cant signup, thank you!

Alan

Collapse
 
rcmlee99 profile image
Roger Lee

Hi Nader, great write up. If I want to redirect to the page I came from using state variable. How can I customise or set the OpenID AuthCode state variable using Auth.federatedSignIn()? Alternatively, do you have any suggestion to redirect to the page I came from assuming that redirect path is fixed and I cannot append to it.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.