DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for AWS Amplify: Using Existing Auth and API Resources
Michael Liendo
Michael Liendo

Posted on

AWS Amplify: Using Existing Auth and API Resources

AWS Amplify is both a CLI toolchain and suite of methods that enable frontend developers to quickly create cloud-based backends while having the scaffolding and best-practices taken care of for them.

For example, if wanting to add a user signup flow to an app, entering the following command will provide guided prompts to accept a default configuration. You can even configure advanced settings.

amplify add auth
Enter fullscreen mode Exit fullscreen mode

Behind the scenes, this sets up an AWS Cognito Pool, as well as an Identity Pool so that user attributes can be stored.

Additionally, if wanting to do the same, but for a RESTful API the following command will trigger a guided prompt to get that configured in your project as well.

amplify add auth
Enter fullscreen mode Exit fullscreen mode

However, for many frontend developers, these resources may be already configured ahead of time by yourself or backend members of your team. Fortunately, the Amplify package allows us to bring in those resources as well.

In this post, let's explore how we can configure a Cognito Pool for user authorization, a RESTful API with ApiGateway, and finally connect those in our application using the AWS Amplify library.


Configuring our Cognito Pool

🚨 I'll be showing off actual secret keys during this post for the sake of learning, however I'll be sure to destroy these resources by the time this post goes live πŸ˜‰

Let's first create our Cognito Pool by logging into the AWS Console and navigating to the AWS Cognito homepage. From there, we'll select the option "Manage User Pools", followed by "Create a user pool" in the top-right corner.

The next screen will ask us to give our user pool a name. I'm going to name mine demopool and select "Review defaults".

aws cognito pool naming page

From here, we can select any of the items we'd like to tweak before creating our user pool.

For this example, I'll select the email configuration section, and change the email message that my users will be sent when verifying their signup.

cognito configuration page

email verification message

🚨When done, remember to click "Save Changes" at the bottom of the page.

Additionally, feel free to add tags, modify the password settings, etc. However, before selecting "Create pool" at the bottom of the page, we'll need to add and configure an App Client so that Amplify can successfully authenticate our frontend. So either from the left panel, or the main area, select "App Clients", and next select "Add an app client".

All we'll need to do here is give our app client a name, and uncheck "Generate client secret". Afterwards, we can select "Create app client" at the bottom.

configure client app

When done, note that we'll need the generated pool id, as well as the app client id that we created earlier, so copy those over for easy access for the time being, and we'll switch over to our project

Setting up an Amplify Project

Chances are, you have the Amplify CLI already installed and configured on your machine, if not, please refer to this video on how to get it setup.

From there, let's open up our terminal, and create a new react application and after changing into the project directory, we'll add a few extra dependencies:

npx create-react-app custom-amplify-demo --use-npm
Enter fullscreen mode Exit fullscreen mode
cd custom-amplify-demo && npm i aws-amplify @aws-amplify/ui-react
Enter fullscreen mode Exit fullscreen mode

With our project scaffolded, and dependencies installed, let's configure Amplify to use our custom auth resource.

In src/App.js, replace the current code with the following:

import React from "react";
import "./App.css";
import Amplify from "aws-amplify";
import { withAuthenticator, AmplifySignOut } from "@aws-amplify/ui-react";

Amplify.configure({
  Auth: {
    region: "us-east-1",
    userPoolId: "us-east-1_T2ZfRqx59",
    userPoolWebClientId: "61l5lp494qnb60ek6h0ohonspp",
  },
});

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <p>welcome!</p>
        <AmplifySignOut />
      </header>
    </div>
  );
}

export default withAuthenticator(App);
Enter fullscreen mode Exit fullscreen mode

Starting with our imports, we're first bringing in the Amplify library so that we can talk to our backend resource. Next, we import a higher-ordered-component called withAuthenticator as well as a component to let us sign out of the app.

From there, we are configuring the Amplify library with the credentials needed for our Cognito Pool. Lastly, we are creating a component that simply renders out a "welcome!" message along with our sign out button. Save the app, and run npm run start so that our app starts on localhost:3000.

Just like that, you should now see the application showing a fully-featured signup form that is absolute positioned on the webpage.

signup form to create an account

Go ahead and sign up for an account. After signing up, check your email for for the verification code. If all went well, your message should contain the content we provided in our Cognito Pool.

Code Verification Email

Go ahead and take the verification code at the bottom of the email, and use it as input for the signup form. Once done, you should be automatically routed to the application.

πŸŽ‰We did itπŸŽ‰

It's worth noting that everything we did in this example could have been done using the CLI that Amplify provides, however the flexibility to use custom resources is a great feature to have regardless!


Configuring Our API Gateway

Our next task is go create a custom REST endpoint. To do this, we'll first create a cloud function (AWS lambda) and assign it to a GET method in API Gateway. This can be particularly useful when wanting to separate your frontend with your infrastructure-as-code, where it's common to create this with Cloudformation, Terraform, or Serverless Framework.

To begin, we'll go back into the AWS Console, and navigate to the AWS Lambda creation page.

🚨 Make sure you are in the same region as your Cognito pool

On this page, we'll give our lambda (cloud function) a name and select create function. Optionally, feel free to adjust the runtime and associated policy if that better suits your use case.

create a lambda

On the following page, we can adjust the response that we'd like to send back to our users when they hit our to-be-created endpoint, and select save.

configure a lambda with a custom response

At this point, we have our lambda created, but we have no way to invoke it. Let's change that by adding API Gateway as a trigger. On the same page, select the Designer dropdown arrow located above the Function code section. Next select add trigger, and choose API Gateway from the select field.

From here, we'll have to configure our API. For this example, we're going to make this a REST API, that will require an API key to use with no additional settings.

configure API Gateway

If all went well, we should get a success message at the top of our page, along with our endpoint and API key at the bottom.

API Verification Page

As is, our API would work as long as we pass in the API Key, however, because we're going to calling our API from the browser on a different domain, we have to enable CORS. Also, API Gateway setup a generic ANY method, but Amplify only supports GET,PUT,DELETE,POST. Let's click the resource name to be taken to API Gateway, where we will do he following:

  1. Configure our API with a single GET method.
  2. Assign the lambda we created earlier to that method.
  3. Protect this route with the API key we created earlier.
  4. Enable CORS on our endpoint
  5. Deploy the API

A step-by-step gif of this process can be found by clicking here

πŸ—’οΈ Given our full API URL: https://n4hgk2fh3h.execute-api.us-east-1.amazonaws.com/default/custom-resource-demo-function

Note that

  • https://n4hgk2fh3h.execute-api.us-east-1.amazonaws.com is our base URL
  • default is the stage name
  • custom-resource-demo-function is the specific endpoint we are hitting

πŸŽ‰We did itπŸŽ‰


Now comes the simple part where we update our frontend code to use our newly created API!

We'll keep it simple where the data from the API will display on the page when a user clicks a button. Go ahead and update your code with the following, bearing in mind to use your own resource credentials.

import React from "react";
import "./App.css";
import Amplify, { API } from "aws-amplify";
import { withAuthenticator, AmplifySignOut } from "@aws-amplify/ui-react";

Amplify.configure({
  //Auth is the same as before
  Auth: {
    region: "us-east-1",
    userPoolId: "us-east-1_T2ZfRqx59",
    userPoolWebClientId: "61l5lp494qnb60ek6h0ohonspp",
  },
  // Add in our new API, "name" can be whatever we want
  API: {
    endpoints: [
      {
        name: "demo",
        endpoint:
          "https://n4hgk2fh3h.execute-api.us-east-1.amazonaws.com/default",
      },
    ],
  },
});

function App() {
  const [apiData, setApiData] = React.useState("");

  const handleClick = async () => {
    const data = await API.get("demo", "/custom-resource-demo-function", {
      headers: {
        //🚨 don't embed api keys in real life!!
        "x-api-key": "grC9ZygLZuaek3hS8Uh6I9rtC5IgYvwd36EAjaba",
      },
    });
    setApiData(data.body);
  };
  return (
    <div className="App">
      <header className="App-header">
       <p>Welcome! My favorite quote is: {apiData}</p>
        <button onClick={handleClick}>Click me!</button>
        <AmplifySignOut />
      </header>
    </div>
  );
}

export default withAuthenticator(App);
Enter fullscreen mode Exit fullscreen mode

If you were logged out of your application, go ahead and log back in. Now click the button and bear the fruits of all your hard work!πŸ»πŸ’

application with json displayed on page


It's worth reiterating, that AWS Amplify's selling point is that it does all of this configuration for us, so that we can focus on our specific business logic✨

However, I've personally used Amplify on projects where the frontend team was a bit silo'd from the backend team, and we relied on the backend to create our resources as a compromise to us using a lot of Amplify's built-in components and methods.

Hope this helps! Be sure to follow for more content on AWS Amplify!

Top comments (4)

Collapse
 
dannygoncalves profile image
Danny Goncalves

Thanks for this, it served me well on a project I was working where the userPool was preconfigured, question, are there any security considerations regarding exposing the userPoolID and userPoolWebClientId in the client code?

Collapse
 
mtliendo profile image
Michael Liendo

Thanks! Regarding security considerations, no--there's nothing inherently bad about exposing it. Of course, less is better πŸ˜‰ but a malicious actor would still need proper AWS credentials (secret key/access token), or IAM Role to perform operations. Awesome question!

Collapse
 
dbhagen profile image
Daniel Hagen

Can you speak to the aspect of changes that Amplify performs depending on additional frontend logic? Specifically, I'm thinking DataSore. Every time I modify the schema for GraphQL (with Auth tags), it wants to update Cognito. This has made me nervous about ejecting it from Amplify, but I need some of the manual controls that Amplify hasn't implemented (email domain, in your example).

Collapse
 
mtliendo profile image
Michael Liendo

You're right that Amplify likes to take control of cognito to perform what it thinks is a best practice and that sometimes that may conflict with what our business logic is trying to do. In my experience, it's best to try and get as far as you can with the CLI and if you find something isn't supported, then to open an issue on the repo to see if it can be put on the roadmap.

Regarding your manual control. If by email domain you meant having a presignup hook that verifes a domain (an allowed, or blocked list for example) the amplify cli does have that built it.

Happy to help out, and if you'd like some more feedback on how it could help, feel free to post any Q's you have in the Amplify discord channel: github.com/aws-amplify/amplify-js/...

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.