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):
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:
- Learn how to sign out users & check the current signed in user
- Adding custom buttons for OAuth providers
- How to add custom form for Username / Password sign in with an example
- 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.