Front-End Web & Mobile

Import existing Amazon Cognito resources with Amplify Admin UI

This blog post was written by Anna Pfoertsch, Senior Product Manager at AWS Amplify.

In this guide you will learn how to integrate your existing Amazon Cognito user pool and federated identities (identity pool) into an Amplify project via the Amplify Admin UI. This will enable your GraphQL API (AppSync), Storage (S3) and other resources to leverage your existing authentication mechanism.

AWS Amplify is the fastest and easiest way to build cloud-powered mobile and web apps on AWS. Amplify comprises a set of tools and services that enables front-end web and mobile developers to leverage the power of AWS services to build innovative and feature-rich applications.

With today’s Amplify CLI release, customers can re-use their existing Amazon Cognito resources for their Amplify project.

Benefits:

  • Authorize user access to fields/tables in the Admin UI’s data model
  • Use the Admin UI to manage users and groups (instead of having to login to the AWS console)
  • Use the imported auth resource across Amplify environments

What we’ll learn:

  • How to use your existing Amazon Cognito resource with the Amplify JS Library’s Authenticator UI component
  • How to authorize your existing users to interface with a new GraphQL API
  • How to manage your users directly from the Admin UI

What we’ll build:

  • A todo application backed by an existing Amazon Cognito user pool

Pre-requisites:

  • Install the latest Amplify CLI version
    • Open terminal and run npm install -g @aws-amplify/cli to update to the latest Amplify CLI.
  • Amplify Admin UI is already configured
  • Have an existing Amazon Cognito user pool and identity pool
    • Make sure your Amazon Cognito user pool has at least two app clients with the following configuration:
      • one app client without a client secret
      • one app client with a client secret
    • You’ll require an identity pool with the both of aforementioned user pool app clients as an authentication provider in order to complete the storage integration showcased at the bottom of the article.

Create an Amazon Cognito user pool and identity pool outside of your Amplify project

You can skip this section if you already have an existing user pool and identity pool.

A user pool is a user directory in Amazon Cognito. With a user pool, your users can sign in to your web or mobile app through Amazon Cognito. Your Amazon Cognito identity pool enables you to create unique identities and assign permissions for users and can include your Amazon Cognito user pool users. You will need both for this tutorial.

Go to the Amazon Cognito console to create a user pool. You can do this by searching for the Amazon Cognito service, and then clicking on “Manage User Pools”. Create a new user pool. For the purposes of this blog, I’ll create a user pool called “test-import-auth” without changing the default settings. Before clicking “Create pool” you have the option to add app clients on the “Review” page.

For this demo, you need to create two app clients since generally an app client corresponds to the separate platforms of an app. For example, you might create an app for a server-side application and a different Android app. Each of these apps has its own app client ID. In our case, make sure to create the following two app clients:

  • “native-client” – an app client with a client secret
  • “web-client” – an app client without a client secret

To do so, click “Add app client”, then “Add an app client”. On this page you can name your app client and decide if you want to generate a client secret or not by selecting the “Generate client secret” option. You can leave all other settings as is.

Once you’ve created your user pool, you can navigate to General settings > App clients to see your “native-client” and “web-client” with their corresponding app client IDs.

Screenshot of Cognito User Pool console's app clients page

To learn more, read “Configuring a User Pool App Client

Now let’s create a new identity pool and use both app clients from “ExistingUserPool” as an authentication provider. Navigate back to your Amazon Cognito console and select “Manage Identity Pools”. Once there, select “Create new identity pool”, name your identity pool. For this demo, I’ve named my identity pool “testIdentityPool”. From there, expand the Authentication providers tab.

Screenshot of Identity Pool console

In the Amazon Cognito tab under Authentication providers, you need to create two providers. Each provider will contain the user pool ID of the user pool you just created (in my case “test-import-auth”). One provider’s App client ID will be you web-client app client ID, and the other will be your native-client app client ID. You can also edit and review these later by going to your identity pool and selecting “Edit identity pool” in the top right corner.

Once done, select “Create Pool”. To learn more, read “Getting Started with Amazon Cognito Identity Pools”.

Import Amazon Cognito resources

To import your Amazon Cognito resources, go the the Authentication page in your app’s Admin UI. By default “Start from scratch” will be selected, choose “Reuse existing Amazon Cognito resources” instead.

Screenshot of Admin UI's import auth flow

Under “Select a Cognito User Pool”, select your user pool. After selecting, you will be prompted to select your app clients. In our case, we’re choosing two separate ones form web and mobile.

Screenshot of select an app client prompt

After this you have the option to select your identity pool.

Screenshot of select an Identity Pool prompt

Once everything is selected, click Import on the bottom of the page.

Upon successful completion of importing:

  • Amplify Library’s configuration file with your Amazon Cognito resource information will be generated upon the next
  • Any other category (api, storage and more) can leverage the imported Amazon Cognito resource as an authentication & authorization mechanism
  • Ability to configure other categories to access the imported resource. For instance, a Lambda function (“amplify add function”) can access this auth resource

Add Login to a React app

Now that we’ve imported our Amazon Cognito resource into our Amplify project, let’s start to leverage it within a UI. Run the following command to create a new React project called “amplify-todo”

npx create-react-app amplify-todo
cd amplify-todo

Let’s pull the Amplify configuration files into your source code by running:

amplify pull --appId <appId> --envName staging

Note: Replace <appID> with your app’s ID. The full command can easily be found by clicking “Local setup instructions” on the top right of your Admin UI and copying the pull command there.

Accept all the default values for the prompted questions.

You should see a new “aws-exports.js” file in the “src/” folder with the Amazon Cognito resource information. Your aws-exports.js file should look something like this:

const awsmobile = {
  "aws_project_region": "YOUR_REGION",
  "aws_cognito_identity_pool_id": "YOUR_IDENTITY_POOL_ID",
  "aws_cognito_region": "YOUR_REGION",
  "aws_user_pools_id": "YOUR_USER_POOL_ID",
  "aws_user_pools_web_client_id": "YOUR_USER_POOL_WEB_CLIENT_ID",
  "oauth": {}
};

In order to take advantage of the imported Amazon Cognito resource. Let’s start adding a login experience around our application. First install the Amplify JS library and its React UI component:

yarn add aws-amplify @aws-amplify/ui-react

Once the dependencies are installed, we have to configure your app to pick up the Amplify configuration generated by amplify push. Do that by adding the following lines to your index.js file:

import Amplify from 'aws-amplify'
import awsconfig from './aws-exports'

Amplify.configure(awsconfig)

Now, we need to update we need to wrap our App component with the higher order component withAuthenticator in the App.js file as shown below. This will automatically configure the UI component to interface with our imported Amazon Cognito user pool.

Add the withAuthenticator to your imports in App.js:

import { withAuthenticator } from '@aws-amplify/ui-react'

Modify the export default statement on the very bottom of App.js

export default withAuthenticator(App)

Let’s build our app and test the login experience by running:

yarn start
Screenshot of local react app

Amplify Authenticator UI components with an imported Cognito user pool

🎉 You should now see a login screen and signing in with an existing user should work right out-of-the-box.

Add a GraphQL API with Amazon Cognito user pool as an auth mechanism

Now that we’ve got our login experience completed, let’s move to creating a new GraphQL API backed by our existing Amazon Cognito resource. This can be done via the Admin UI. Go to the Data modeling page via the table of contents. Once there, add a new model titled “Todo”. In total, you should have 3 fields

  • “id”, type: ID! (created by default)
  • “name”, type: String
  • “description”, type”: String

Screenshot of Admin UI data modeling

Change the authorization mode to “Cognito user pool”. Ensure that your Authorization rules are according to how you want your data to be viewed / edited. Take a close look at each scopes’ permissions.

Screenshot of Admin UI's auth mode selector

To update your source code, run the following command:

amplify pull

Then run the following

amplify codegen add

This will add the required GraphQL files to your source code.

Let’s tweak your app component to create a simple “todo” app. Replace your App.js file with the following content:

/* src/App.js */
import React, { useEffect, useState } from 'react'
import { withAuthenticator } from '@aws-amplify/ui-react';
import { API, graphqlOperation } from 'aws-amplify'
import { createTodo } from './graphql/mutations'
import { listTodos } from './graphql/queries'

const initialState = { name: '', description: '' }

const App = () => {
  const [formState, setFormState] = useState(initialState)
  const [todos, setTodos] = useState([])

  useEffect(() => {
    fetchTodos()
  }, [])

  function setInput(key, value) {
    setFormState({ ...formState, [key]: value })
  }

  async function fetchTodos() {
    try {
      const todoData = await API.graphql(graphqlOperation(listTodos))
      const todos = todoData.data.listTodos.items
      setTodos(todos)
    } catch (err) { console.log('error fetching todos') }
  }

  async function addTodo() {
    try {
      if (!formState.name || !formState.description) return
      const todo = { ...formState }
      setTodos([...todos, todo])
      setFormState(initialState)
      await API.graphql(graphqlOperation(createTodo, {input: todo}))
    } catch (err) {
      console.log('error creating todo:', err)
    }
  }

  return (
    <div style={styles.container}>
      <h2>Amplify Todos</h2>
      <input
        onChange={event => setInput('name', event.target.value)}
        style={styles.input}
        value={formState.name} 
        placeholder="Name"
      />
      <input
        onChange={event => setInput('description', event.target.value)}
        style={styles.input}
        value={formState.description}
        placeholder="Description"
      />
      <button style={styles.button} onClick={addTodo}>Create Todo</button>
      {
        todos.map((todo, index) => (
          <div key={todo.id ? todo.id : index} style={styles.todo}>
            <p style={styles.todoName}>{todo.name}</p>
            <p style={styles.todoDescription}>{todo.description}</p>
          </div>
        ))
      }
    </div>
  )
}

const styles = {
  container: { width: 400, margin: '0 auto', display: 'flex', flex: 1, flexDirection: 'column', justifyContent: 'center', padding: 20 },
  todo: {  marginBottom: 15 },
  input: { border: 'none', backgroundColor: '#ddd', marginBottom: 10, padding: 8, fontSize: 18 },
  todoName: { fontSize: 20, fontWeight: 'bold' },
  todoDescription: { marginBottom: 0 },
  button: { backgroundColor: 'black', color: 'white', outline: 'none', fontSize: 18, padding: '12px 0px' },
  hr: { width: '100%', height: 1 }
}

export default withAuthenticator(App)

Let’s run your app (yarn start) and try opening your app also in an Incognito window where you can login with a different account to see the owner-based authorization in action.

Screenshot of side-by-side todo list

Each user should now be able to see their own list of Todos!

Manage your users from the Admin UI

Your user can easily be managed from the Admin UI. To do so, go to the User management section in the Admin UI. From here you can view, manage, and even create new users.

Screenshot of Admin UI's User Management Screen

If you wanted to enable someone new to log in to the Todo app, all you have to do is select “Create user” and fill out the text boxes with their credentials. This user will then receive a confirmation email to their email address with their temporary password and username.

Screenshot of user creation

🥳 Success!

Congratulations! You’ve got a fully functioning Amplify project up and running with your existing Amazon Cognito user pool and identity pool. With a few clicks, you were able to build out authentication for your existing user base, and even manage your users.

If you’re looking for more information like multi-environment support and how to unlink an imported resource, please review our documentation. If you have any feedback or enhancement requests, please create an issue in the Github repository.