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.
Top comments (55)
Hey, great article! any news on the react native version?
React Native article is way late, but available at dev.to/dabit3/the-complete-react-n...
Any update on the React Native version ?
Been trying to make it work but stuck at when the hosted UI (using withOAuth + Amplify) get me back to my app (hard link), Hub.Listen doesn't seems to fire with the signIn event, so my app doesn't know that the user is logged or not. If I check on Amazon Incognito, the Facebook user as been added to the pool, so that part seems ok.
Thanks !
Check out dev.to/dabit3/the-complete-react-n...
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
});
Hi Nader,
This is awesome, just like what we need in time.
But I encounter some problems, why is the CLI not working in Git Bash?
And when I use windows command prompt, and type
amplify add auth
it will always return to my prompt after the first step.I use windows 10 and latest CLI.
Thanks.
Hi Abraham, I'm sorry you're having issues with the CLI in that environment. I would suggest opening a GitHub issue at github.com/aws-amplify/amplify-cli... & giving us your system & env info to see if we can figure out what issue you're having.
Hello again,
I check Github and found the answer.
Turns out I need to update NodeJS to version 11 or 12.
I don't know why this is not working with Node10, but everything seems good now.
Thanks.
Does Amplify support Cognito + a custom OIDC provider (e.g. yahoo/twitch/salesforce?) such that the access token from the OIDC provider (not Cognito) will be returned for interacting with said OIDC's API? I only receive tokens for use with Cognito which is only half of what I'm trying to obtain.
No, you also have to create your own Lambda function to do that: such that github.com/arelaxend/fays-openid
Hi Nader,
Thank you for this article, it helped me a lot.
I am trying to adapt it, sign up with Google (OAuth) or with Cognito (email + password).
My issue is that if I sign up with Google and then Cognito, I create a duplicate in my User Pool. Also, if I sign up with Cognito and then Google, it also create a duplicate in my User Pool.
However, if I try to sign up twice with Cognito, it would notice the email already exist.
I am trying to find a good way to prevent those duplicate, or by raising an error or by merging the duplicate but I have not found out, would you have suggestions?
Thank you
If you use Auth.federatedSignIn({provider: 'Google'}), you don't have to use anything else.
Why twice ?
Hi rudyhadoux,
If you sign in with Facebook and Google with same email, it creates two identities.
Thanks.
Two Cognito identities with the same email ?
Is it possible ?
Hi Adrien,
Did you find a solution to this problem?
Thanks.
Cheers for this: I hadn't thought to look at Hub to support Auth, it very neatly solves one of the problems I'm working on at the minute, this came at just the right time!
I've found Amplify very useful so far: only major pain point has been that the CLI has proven effectively useless for me, as the way we have our resources set up means I never want automatic provisioning -- being able to say to the CLI "I want to use this AppSync API + this Cognito Pool + etc etc" would be incredibly useful (particularly w/r/t generating the configs + the AppSync GQL codegen functionality).
Hey Dan, thanks for the feedback, this is great! I'm passing this on directly to the team. Hopefully we can get something figured out & on our roadmap that will address this.
Hi Nader, thanks a lot for providing the simple/short article to bring beginner up to speed.
Can you give a detailed under the hood mechanism explanation to how 'the redirect signin URI: localhost:3000/' is used during the sign-in process? In a production code, I assume this URI should be changed, right? But to be changed to what?
I guess I would like to understand how the following three URL and web app / web browser interact during the Oauth signed process to fully understand it.
Can you give a detailed walk through of how each URI during a life of Social Sign In process.
Thanks
For those who have issue with the redirect URLs or want to add more than one redirect URLs for dev, prod, localhost, here is a closed topic: github.com/aws-amplify/amplify-js/...
You can find a demo here that also work in localhost / online: master.d3h5j4begww46c.amplifyapp.com/
And a github fork (from dabit3): github.com/arelaxtest/amplify-auth...
Hi Nader,
Alan
Great article !
Is there any way so that i don't have to use Amazon Cognito ? We have separate user authentication system and I need to upload files from frontend to s3 directly.
If I don't add auth in the configure part then i am getting
No Credentials
. So Can i use normal aws IAM user to access S3 using Amplify ?Some comments may only be visible to logged-in visitors. Sign in to view all comments.