Secure the API endpoints using the JWT authorizer via Amazon Cognito User Pools
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!!
Legends:
- Login to Cognito in hosted UI/Custom web app using the credentials.
- Cognito returns an access token.
- The browser sends a pre-flight OPTIONS request to confirm access for the current domain (CORS check).
- API Gateway invokes the CORS Lambda for CORS check.
- Lambda returns 200 response if the domain is valid.
- API gateway sends 200 response to the client.
- The client sends the API request with an access token (got in step -2) as a header to the API Gateway.
- API Gateway sends a request to Cognito for an access token and scope validation.
- Cognito responds OK and returns token validity if the access token is valid.
- Now, the client request invokes the backend resource.
- Backend response to the API Gateway.
- Backend response from API Gateway to the Client.
Instructions
- Go to Cognito and quickly grab the User Pool ID and client ID of your app integration.
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, includingOPTIONS
requests. - In HTTP APIs, the route
OPTIONS /{proxy+}
has higher priority than$default
route. Thus setting the route this way enables clients to submitOPTIONS
requests without authorization, and hence the backend then returns CORS headers which takes care of the CORS issues here.
Happy hitting!
Refer:
3. AWS-Doc