API Gateway Responses and Handling Authorizer Responses
Tags: aws, apigateway, help, node
Published: 2023-05-04 01:44:39

## Intro
I have added a **token-based Lambda Authorizer** for all my backend services deployed on API Gateway. I wanted the user to be signed out if the authorizer responds with a **401** (Unauthorized) or **403** (Access Denied) error.

This is how my code looked like for the authorizer lambda:
```js
const jwt = require('jsonwebtoken');

exports.handler = function (event, context, callback) {
  const token = event.authorizationToken?.split(' ')[1];

  if (!token) {
    callback('Unauthorized'); // Return a 401 Unauthorized response
  }

  const data = jwt.verify(token, process.env.SECRET, (err, data) => {
    if (err) {
			// Return a 403 Access Denied response
      callback(null, generatePolicy('user', 'Deny', event.methodArn, {"messageString":"Invalid token"}));
    }
    return data;
  });
  
  callback(null, generatePolicy('user', 'Allow', event.methodArn, data));
};

// Help function to generate an IAM policy
const generatePolicy = function (principalId, effect, resource, data) {
  const authResponse = {};

  authResponse.principalId = principalId;
  if (effect && resource) {
    const policyDocument = {};
    policyDocument.Version = '2012-10-17';
    policyDocument.Statement = [];
    const statementOne = {};
    statementOne.Action = 'execute-api:Invoke';
    statementOne.Effect = effect;
    statementOne.Resource = resource;
    policyDocument.Statement[0] = statementOne;
    authResponse.policyDocument = policyDocument;
  }

  // Optional output with custom properties of the String, Number or Boolean type.
  authResponse.context = {
    ...data,
  };
  return authResponse;
};
```

After this, I used to get error logs on my client apps, but I could not access the response object to check the response's status code. 

I needed to determine if an error was caused by my authorizer (resulting in a 401 or 403 status code) or by my API endpoint lambdas. The issue was that the response was being caught as a <u>fetch error</u> in the <u>catch block</u> instead of returning a response with the expected status code and message that I could handle properly.

Additionally, I guess it was even giving me a **CORS** error, which I wasn't able to understand why.

## Solution

After quite a bit of searching, I found out that to receive proper handleable responses, I would need to configure the <u>**API Gateway Responses**</u> section in the API Gateway.

![gateway responses](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a7ewvcm4heharyrhnwkm.png)


Here, you can see all of the responses the API Gateway is capable of handling.

Add the **CORS headers** in the response header to receive proper handleable responses and configure the response templates as you need.

In my case, this is how I configured my Access Denied:


![access_denied api gateway response config](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5xiyz1dgfh2eirgvpynr.png)



**#Note**: Here, the `messageString` comes from the context data that we are sending from our **Authorizer function** that we defined previously.

```js
.
.
.
if (err) {
	// Return a 403 Access Denied response
  callback(null, generatePolicy('user', 'Deny', event.methodArn, {"messageString":"Invalid token"}));
}
.
.
.
  authResponse.context = {
    ...data,
  };
}

```

### For more info:
[https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html#api-gateway-gatewayResponse-definition](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-gatewayResponse-definition.html#api-gateway-gatewayResponse-definition)