Authorization with API Gateway, Cognito and React

I've been experimenting with using Amazon Cognito User Pools in conjunction with the Amplify Javascript library to handle user authentication in our Single Page applications. One of the problems I ran into was finding a way to restrict my API to only be accessible to authorized users. Cognito, API Gateway, and Amplify made this easy to do.

Configure API Gateway

From your API Gateway settings in the AWS Console, select Authorizers, and then choose Create new authorizer.

Enter in the name and domain of your AWS Cognito User pool.

Under Token Source add Authorization.

It should look something like this:

api-gateway=authorizer

Next, go to the method that you’d like to restrict, and select Method Request. The new authorizer that you created should now be listed. Go ahead and select it, and deploy your newly authorized API.

Once the API is deployed, you should verify that it is indeed being restricted. Curl the deployed URL, and you should get back a 403 that looks like this:

{
  message: "Missing Authentication Token"
}

Set up Amplify

Follow the Amplify guide to configure your client application to work with your Cognito user pool. In this example, I added mine to a React application.

Let's say you have a component that makes an API call and retrieves items after it has mounted.

import React, {useEffect} from 'react';
import {Auth} from 'aws-amplify';
import {fetchItems} from './myApiHelpers.js';

function TodoList(props) {
  const [items, setItems] = useState([]);

  useEffect(() => {
    Auth.currentAuthenticatedUser(user => {
      user.getSession((err, session) => {
        if(err) {
          throw new Error(err);
        }

        const sessionToken = session.getIdToken().jwtToken;

        fetchItems(sessionToken)
          .then(setItems)
          .catch(err => console.log(err));
      });
    });
  }, []);

  return (
    <ul>
      items.map(item => <li key={item.id}>{item.name}</li>);
    </ul>
  );
}

The key here is that Amplify gives you a method to get the JWT Token containing claims about the identity of the authenticated user. This is the token that the API Gateway Authorizer is expecting the client to send.

Finally, in your function to fetch the items, make sure to set the Authorization header to the JWT token generated in the above function.

export function fetchItems(sessionToken) {
  return fetch('https://my-api-gateway-url.com/items', {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': sessionToken
    }
  }).then(response => response.json());
}

That's it! Your application should now be able to make requests to your API Gateway endpoints.

by Ryan Billings