Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throw custom error message from API Gateway custom authorizer

Here in the blue print says, API gateway will respond with 401: Unauthorized.

I wrote the same raise Exception('Unauthorized') in my lambda and was able to test it from Lambda Console. But in POSTMAN, I'm receiving status 500 with body:

{   message: null` }  

I want to add custom error messages such as "Invalid signature", "TokenExpired", etc., Any documentation or guidance would be appreciated.

like image 620
Tenzin Chemi Avatar asked Dec 21 '17 09:12

Tenzin Chemi


People also ask

How do I return custom HTTP status codes from a Lambda function in Amazon API gateway?

The easiest way to set custom HTTP status code is to setup a Lambda Proxy Integration in API Gateway. In API Gateway > Resource > Actions Dropdown > Create Method > tick Lambda Proxy Integration and select appropriate Lambda function. For async functions just return with an object with statusCode and body .

What should be returned from an API gateway authorizer?

If the API uses a usage plan (the apiKeySource is set to AUTHORIZER ), the Lambda authorizer function must return one of the usage plan's API keys as the usageIdentifierKey property value.

How do I send error response in Lambda?

For API Gateway to pass the error type (for example, InvalidParameterException ), as part of the response to the client, the Lambda function must include a header (for example, "X-Amzn-ErrorType":"InvalidParameterException" ) in the headers property.

How do I return a response from Lambda to API gateway?

There is no need to map the Lambda function response to its proper HTTP response. To return the result to the client, set up the integration response to pass the endpoint response through as-is to the corresponding method response. Or you can map the endpoint response data to the method response data.


2 Answers

This is totally possible but the docs are so bad and confusing.

Here's how you do it:

There is an object called $context.authorizer that you have access to in your gateway responses template. You can read more about it here: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html

Here is an examample of populating this authorizer object from your authorizer lambda like so:

// A simple TOKEN authorizer example to demonstrate how to use an authorization token   // to allow or deny a request. In this example, the caller named 'user' is allowed to invoke   // a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke   // the request if the token value is 'deny'. If the token value is 'Unauthorized', the function   // returns the 'Unauthorized' error with an HTTP status code of 401. For any other token value,   // the authorizer returns an 'Invalid token' error.     exports.handler =  function(event, context, callback) {      var token = event.authorizationToken;      switch (token.toLowerCase()) {          case 'allow':              callback(null, generatePolicy('user', 'Allow', event.methodArn));              break;          case 'deny':                            callback(null, generatePolicy('user', 'Deny', event.methodArn));              break;          case 'unauthorized':              callback("Unauthorized");   // Return a 401 Unauthorized response              break;          default:              callback("Error: Invalid token");       }  };           var generatePolicy = function(principalId, effect, resource) {              var authResponse = {};                            authResponse.principalId = principalId;              if (effect && resource) {                  var policyDocument = {};                  policyDocument.Version = '2012-10-17';                   policyDocument.Statement = [];                  var 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 = {                  "stringKey": "stringval custom anything can go here",                  "numberKey": 123,                  "booleanKey": true,              };              return authResponse;          }

They key here is adding this part:

// Optional output with custom properties of the String, Number or Boolean type.          authResponse.context = {             "stringKey": "stringval custom anything can go here",             "numberKey": 123,             "booleanKey": true,         }; 

This will become available on $context.authorizer

I then set the body mapping template in gateway responses tab like this:

{"message":"$context.authorizer.stringKey"} 

NOTE: it must be quoted!

finally - after sending a request in postman with Authorization token set to deny I now get back a payload from postman that looks like this:

{     "message": "stringval custom anything can go here" } 
like image 158
maxwell Avatar answered Sep 25 '22 23:09

maxwell


I used @maxwell solution, using custom resource ResponseTemplates. For deny response see below:

{   "success":false,   "message":"Custom Deny Message" } 

You can check this out here: https://github.com/SeptiyanAndika/serverless-custom-authorizer

like image 25
Septiyan Andika Avatar answered Sep 23 '22 23:09

Septiyan Andika