Set up an AWS Amplify app with Google Sign In

JB
Level Up Coding
Published in
10 min readJul 11, 2021

--

This article discusses how to set up an Amplify app with Google Sign In using a React app frontend. This will also mention how to configure multiple redirect URIs per app.

The first section is dedicated to boilerplate setup with React, Github, Amplify, and the Google developer console, while the second is about adding auth.

/** Skip the setup step if you’ve created an app already, and move right to the heading Add auth to Amplify app */

Set up React and Amplify

1. Create a new React app and GitHub repo, add a project in the Google developer console

On the command line

  • Create a react app with npx create-react-app google-test, cd into the app, and run npm start to start it on your local machine.
  • Create a new repo in GH for the app and push it to this repo.

In the AWS console

  • Log into the AWS console and find the Amplify service.
  • On the main Amplify page, select Get started and Deliver to create a web app or from the apps page, select New app and Web app.
  • Select GitHub as the provider.
  • Auth with GH if you haven’t.
  • Choose repo and branch main.
  • Select default build settings. I use npm as a package manager so I changed from yarn to npm in the npm start and npm run build commands.
  • Save.

Your GH repo will be synced with the Amplify instance and continuous deploy will be set up —

In Google developer console

  • Create a project and name it.
  • In the APIs and Service page, select the Oauth consent screen tab.
  • Set up OAuth consent screen with the required fields—these can all be changed later.
  • Select the Credentials tab → Create credentials→ Oauth client ID
  • Name the project and save it to get Oauth client ID and secret. I downloaded it as JSON to easily access it later.

2. Set up Amplify in the React app

On the command line

  • npm install -g @aws-amplify/cli — install the Amplify CLI, which allows you to use CLI commands prefixed with amplify.

In the AWS console

  • In your project page, click the Backend env tab → Get started. This will initialize a backend environment.
  • When it finishes, click the Local setup instructions dropdown and copy the CLI command: amplify pull --appId {appId} --envName staging

On the command line

  • Run the copied command.
  • Sign in the Amplify Admin UI in the browser.
  • Select the defaults, or the applicable choices for your project, from the options listed.
? Choose your default editor: Visual Studio Code
? Choose the type of app that you're building javascript
Please tell us about your project
? 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 plan on modifying this backend? Yes
  • amplify pull
  • npm install aws-amplify

Add auth to the Amplify app

1. Add auth to the Amplify backend and finish setting up the Google Oauth consent screen

On the command line

  • amplify add auth — we’re now adding the auth infrastructure to our app!
  • It will present a list of options—select Default configuration with Social Provider (Federation) to use social sign on with direct sign in, and select how else you want users to be able to authenticate (email, username, phone number).
Do you want to use the default authentication and security configuration? Default configuration with Social Provider (Federation)
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Email
Do you want to configure advanced settings? No, I am done.
What domain name prefix do you want to use? googlesignin
Enter your redirect signin URI: https://main.dpdzznty4hgmh.amplifyapp.com/
? Do you want to add another redirect signin URI Yes
Enter your redirect signin URI: http://localhost:3000/
? Do you want to add another redirect signin URI No
Enter your redirect signout URI: https://main.dpdzznty4hgmh.amplifyapp.com/
? Do you want to add another redirect signout URI Yes
Enter your redirect signout URI: http://localhost:3000/
? Do you want to add another redirect signout URI No
Select the social providers you want to configure for your user pool: Google
  • For the domain name prefix, you can use the default given, I just had a protected word, aws in mine so I had to change it.
  • For the redirect signin/signout URIs add, the URL of the Amplify app, which you can find the Frontend environments tab, with a structure like main. ... .amplifyapp.com. I added two redirect signin/signout URIs, one for the “deployed” URL, and one for localhost to test auth on my local machine.
  • amplify push

Q: What is a redirect signin/signout URI?

⁉️ A: When a user clicks Sign In with Google, they are taken to a page operated by Google, where their Google credentials are validated. If you look at the URL of this page it’s something like: accounts.google.com/o/oauth . This means that once sign up is complete, the user has to be pushed back to the main site. This URL defines where that user will be pushed.

In React > src folder

  • Once the updates are pushed, the aws-exports.js file in the /src folder in will have updated with the Oauth config set in Amplify.
  • Copy the domain in the oauth object, e.g. googlesignin-staging.auth.us-east-2.amazoncognito.com

In Google developer console

  • Credentials tab → Oauth 2.0 Client IDs → Click the pencil icon to edit your project.
  • Add the copied domain as an authorized Javascript origin and redirect URI. At the end of the domain in the redirect URIs section, add /oauth2/idpresponse . This is not configurable, so you must add that fragment exactly.

Q: What is the /oauth2/idresponse fragment for?

⁉️ A: This is an existing endpoint from Amplify that handles redirects during Oauth sign in. Because your Amazon Cognito user pool URL is associated with your app, it can use this endpoint to send your users to the redirect you specified in your Amplify configs.

Use Sign In with Google on the frontend

1. Configure index.js to listen to multiple redirect URIs

  • First we will import Amplify and the auth config into the React app and add some conditionals to detect which redirect signin/signout URI we will use by env.
  • I roughly used the code example outlined in the Amplify docs here, under the Redirect URIs heading.

index.js

// add to existing imports
import Amplify from 'aws-amplify';
import config from './aws-exports';
// check if env is localhost or not
// if you're not developing on localhost, you will need to detect this is another way—the docs linked above give some examples.
const isLocalhost = !!(window.location.hostname === "localhost");
// split redirect signin and signout strings into correct URIs
const [
productionRedirectSignIn,
localRedirectSignIn ] = config.oauth.redirectSignIn.split(",");
const [
productionRedirectSignOut,
localRedirectSignOut ] = config.oauth.redirectSignOut.split(",");

// use correct URI in the right env
const updatedAwsConfig = {
...config,
oauth: {
...config.oauth,
redirectSignIn: isLocalhost
? localRedirectSignIn
: productionRedirectSignIn,
redirectSignOut: isLocalhost
? localRedirectSignOut
: productionRedirectSignOut, }
}

Amplify.configure(updatedAwsConfig);

You could avoid having multiple redirect URIs by ONLY enabling the auth to work on dev or production envs… but this seems like it will make testing/deployment more difficult.

  • Some basic UI is needed to finish the example. I ran npm i skylight-react to use a basic component library I made, but the components used are up to you! To use the AWS UI library, install the @aws-amplify/ui-react package too… I think this UI library is Simply Drab, but that’s subjective.
  • We will configure App.js to check if a user exists on each page refresh using the Amplify Auth class and listen for the auth events sign in and sign out using the Hub, which is an event listener component.

2. Listen for auth and store user in state

This sets up a basic config where if there is a user, they are directed to <UserHome/> and if not, a generic <Landing/> page.

  • I’m storing the user in simple useState for this example, but larger apps would store the user with the useContext hook or a state management library.

App.js

import React, { useEffect, useState } from 'react';
import { Hub, Auth } from 'aws-amplify';
import { Loader } from 'skylight-react';
import './App.css';
import 'skylight-react/dist/skylight.css';
import Landing from './modules/Landing';
import UserHome from './modules/UserHome';
function App() {// init state to store user and show loader const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);

// get user
async function getUser() {
try {
const token = await Auth.currentAuthenticatedUser();
setLoading(false);
setUser(token);
} catch(err) {
console.log(err);
setLoading(false);
}
}
//listen for sign in + out events, if neither are happening check if user exists useEffect(() => {
Hub.listen('auth', ({ payload }) => {
if (payload.event === 'signIn') {
return getUser();
}
if (payload.event === 'signOut') {
setUser(null);
return setLoading(false);
}
});
getUser();
}, []);

// show loading screen while fetching, otherwise return page
if(loading) return <Loader/>return (<div className="App"> {user ? <UserHome email={user.attributes.email}/> : <Landing/>}</div>)};export default (App);
  • We check for the user on each sign in event or any pageload without a signout event. The currentAuthenticatedUser() method returns a CognitoUser class that has information about the user and their metadata. This object looks like this:
  • The attributes property is an object that contains information about the user, like email. This is how to use the user.attributes.email properties to get the user’s email on the frontend.
  • If there is no auth user, nothing will be returned.
  • See the resources section at the bottom for the dev docs to the Hub and Auth.

3. Make the Sign in with Google button and add to a landing page

  • Download the assets or get the specs for the button from Google here.
import React from 'react';
import { Auth } from 'aws-amplify';
import btn from '../../assets/auth/btn_normal.png';
const GoogleSignIn = () => {return (<button onClick={() => Auth.federatedSignIn({ provider:"Google" })}><img src={btn} alt="Google Sign In button" className="googleSignIn" style={{height:"45px", width:"190px"}}/></button>);}export default GoogleSignIn;

Landing.js

import React from 'react';
import GoogleSignIn from './auth/GoogleSignIn';
import { Flex } from 'skylight-react';
const Landing = () => {return (
<Flex column center middle gap={1} height="100vh" width="100%">
<h3>Authenticate to continue</h3><GoogleSignIn/></Flex>);
}
export default Landing;
  • Create a basic page for the authenticated users.
  • Show the user’s email on the screen to prove they’re logged in.

4. Create a protected page only available to auth users

UserHome.js

import React from 'react';import { Flex } from 'skylight-react';const UserHome = ({ email }) => {return (<Flex center middle height="100vh" width="100%" gap={1}><h3>Hello, {email}.</h3><p>This route is for protected users :~)</p></Flex>);}export default UserHome;
  • Push to GitHub and wait for the changes to sync in Amplify.
  • This should work on both the URL given to us by AWS and localhost:3000!
Super basic landing page for anon users
  • Click Sign in with Google
Google Oauth screen
  • Notice the name on the Oauth screen is amazoncognito.com, and not the app name configured. This is because our app is an unverified external app, and will have to be verified with Google to use the display name.
  • Choose an account and be authenticated.
We’re in…
  • To see the user, go to the Cognito service in the AWS console and click on User Pools → select your project → Users and groups
The only, the lonely user

Here is our single user!

We are effectively done this guide. Some final things to think about …

  • Amazon uses local storage to store ID, access, and refresh tokens. All of these can be seen by opening up local storage in your browser’s dev tools, inspecting it in JS, or running const session = await Auth.currentSession() and viewing session.
  • Access and id tokens are 60 minutes by default but can be up to one day. Source.
  • Refresh tokens can refresh access for 30 days since issue time, but can be set for 60 minutes to 10 years. Source.

Amplify references:

Amplify Oauth implementation docs—very comprehensive, see code examples

Auth docs ⚫️ Explanation of user retrieval methods—this is useful because the Auth API docs are poor

Hub docs ⚫️ Full list of Hub auth events that may be listened

Google Sign In button dev documentation

Social sign on references:

AWS | Social provider federation under the hood

Medium | How social authentication works

Auth0 | Learn social login

Okta | What the heck is Oauth?

--

--