'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.



Solution 1:[1]

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"
}

Solution 2:[2]

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

Solution 3:[3]

I'm not sure what is causing the 500 message: null response. Possibly misconfiguration of the Lambda function permissions.

To customize the Unauthorized error response, you'll set up a Gateway Response for the UNAUTHORIZED error type. You can configure response headers and payload here.

Solution 4:[4]

Maxwell is mostly correct. I tried his implementation and noticed that his message should go from :

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

to

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 maxwell
Solution 2 maxwell
Solution 3 jackko
Solution 4 Andrew Argraves