Using AWS Cognito to authorize access to API Gateway

Using AWS Cognito to authorize access to API Gateway

I’m writing a simple web application that at the moment basically does this:

  1. In the web app, users log in
  2. The web app contacts AWS Cognito for user authentication. In AWS Cognito, I’ve set up a user pool, think of it as a database, in which my users are stored. When a user sign in, AWS Cognito checks the user pool to verify the password.
  3. AWS Cognitor responds with different JWT tokens, including an ID token for the user
  4. The web app extracts the ID token, and passes this on to an AWS API Gateway. The API Gateway is set up with the above mentioned AWS Cognitor user pool as authorizer, meaning that only users that are member of that particular pool are allowed to contact the actual API. (In my case the API service is written in Python, using zappa.io)

The AWS documentation is massive, and as the details on how things fit together wasn’t necessarily easy to find, so I though I’d do a quick write-up here just in case others can benefit from it.

Now that the general flow of events are established, let’s dive into a couple of details. First, the frontend app, which is written in Angular, uses AWS Amplify for user signup and user login. This is the configuration for Amplify:

import Amplify from 'aws-amplify';

Amplify.configure({
    Auth: {
        identityPoolId: '<id>',
        region: '<region>',
        userPoolId: '<id>',
        userPoolWebClientId: '<id>',
    },
    API: {
        endpoints: [
            {
                name: "dev",
                endpoint: "http://path/to/my/api"
            }
        ]
    }
});

When a user is logged in, one can use the Amplify SDK to fetch the user’s ID token, so that Angular can pass this token on to the API:

import { Auth } from 'aws-amplify';

Auth.currentSession()
  .then((response) => {
      const idTokenJSON = response.getIdToken();
      const idToken = idTokenJSON["jwtToken"];

      const headers = {
        Authorization: idToken
      };
      let apiName = 'dev';
      let path = '/';
      let init = {
        headers: headers,
        response: true,
      };

      API.get(apiName, path, init).then(response => {
        console.log("Response from the API: " + JSON.stringify(response["data"]["message"]));
      }).catch(error => {
        console.log("Failed to contact " + apiName + ": " + error);
      });

When reaching API, AWS Api gateway verify the token. Authorized users are passed on to the actual API, which may utilize the data contained in the token:

import request, jwt

@app.route("/")
def my_function():
    encoded_jwt = request.headers["Authorization"]
    decoded_jwt = jwt.decode(encoded_jwt, '', verify=False)
    
    email = decoded_jwt["email"]
    username = decoded_jwt["cognito:username"]
    
    return f"Hello, {username} with email {email}!"
        

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: