Secure the API endpoints using the JWT authorizer via Amazon Cognito User Pools

The Optimizer
4 min readApr 27, 2023

--

Hola!

In the process of developing APIs, authentication plays a critical role in keeping the APIs secure.

Do you know?

We can offload API authentication to a managed service by AWS instead of handling it in code. This implementation is another security layer over CORS so that your backend is secure, only members of Cognito can access the backend.

Let’s get our hands dirty!!

Request flow

Legends:

  1. Login to Cognito in hosted UI/Custom web app using the credentials.
  2. Cognito returns an access token.
  3. The browser sends a pre-flight OPTIONS request to confirm access for the current domain (CORS check).
  4. API Gateway invokes the CORS Lambda for CORS check.
  5. Lambda returns 200 response if the domain is valid.
  6. API gateway sends 200 response to the client.
  7. The client sends the API request with an access token (got in step -2) as a header to the API Gateway.
  8. API Gateway sends a request to Cognito for an access token and scope validation.
  9. Cognito responds OK and returns token validity if the access token is valid.
  10. Now, the client request invokes the backend resource.
  11. Backend response to the API Gateway.
  12. Backend response from API Gateway to the Client.

Instructions

  1. Go to Cognito and quickly grab the User Pool ID and client ID of your app integration.
User pool ID
Client ID

2. Navigate to API-Gateway → Authorization → Select your route → Create and attach authorization.

The audience is the Client ID of the App Integration and Issuer URL should be in the format of

https://cognito-idp.region.amazonaws.com/UserPoolID

3. After these configurations when you try to call your API, It will say Unauthorized.

4. To access the API, we have to pass an access token we get after logging into the app(where we are using the Cognito) as a header(Authorizer) to authenticate.

5. After authentication, you will be able to access the API.

Issues Faced :

After enabling the authentication your application throws a CORS issue because the browser initially sends the OPTIONS request (preflight) to confirm the CORS access only if it receives 200 for the OPTIONS request it will send the authentication token for authorization then access to API is possible.

Solution:

Enable CORS and configure a greedy route OPTIONS /{proxy+} without specifying an authorizer. This route will also need an integration to return CORS headers, to prevent a 404.

You have to create a lambda that sends 200 for the options request. Add the following code(Python)

import json

def lambda_handler(event, context):

return { "httpStatus": 200, "headers": {"Access-Control-Allow-Origin": "*"}, "body": json.dumps(event) }

How does this work?

When you enable CORS and authorization for the $default route, there are some special considerations.

  • The OPTIONS method is only for preflight requests hence it neither expects nor requires authorization. However, the $default route on HTTP API catches requests for all methods and routes that you haven’t explicitly defined, including OPTIONS requests.
  • In HTTP APIs, the route OPTIONS /{proxy+} has higher priority than $default route. Thus setting the route this way enables clients to submit OPTIONS requests without authorization, and hence the backend then returns CORS headers which takes care of the CORS issues here.

Happy hitting!

Refer:

  1. Youtube-Video
  2. Blog

3. AWS-Doc

4. Stackoverflow

--

--

The Optimizer
The Optimizer

Written by The Optimizer

Cloud & DevOps👨‍💻 | AWS☁️| K8s⚔️| Terraform🏗️ | CI/CD🚀| Open Source 🐧 | Versatile DevOps engineers. Well-versed with DevOps Tools and Cloud Services.

No responses yet