API Gateway custom authorizer does not parse valid JSON Policy document

0

I've created a Lambda custom authorizer using the Token integration method. The Lambda function returns a policy document in the format shown here:

{
"principalId": "tretre",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:<account>:iz0blsxnql/ESTestInvoke-stage/GET/"
}]
}
}

I've validated the JSON and that it matches the examples shown in the documentation here:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html

However, when I test the authorizer from API Gateway, I consistently get an error of the form:

Can not construct instance of com.amazonaws.backplane.executioncore.frontend.authorizer.CustomAuthResponse: no String-argument constructor/factory method to deserialize from String value

I can see in the log that the Lambda function is invoked and returns the expected JSON policy document. However, API Gateway does not parse it and instead returns the above error. What is the expected form of the policy document returned from a custom authorizer?

Here is the full execution log from API Gateway:

Execution log for request 5ae163c2-f114-4248-b04d-189159a53f43
Mon May 04 14:22:38 UTC 2020 : Starting authorizer: rl311v for request: 5ae163c2-f114-4248-b04d-189159a53f43
Mon May 04 14:22:38 UTC 2020 : Incoming identity: ***tre
Mon May 04 14:22:38 UTC 2020 : Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:<account>:function:BearerTokenAuthorizer/invocations
Mon May 04 14:22:38 UTC 2020 : Endpoint request headers: {x-amzn-lambda-integration-tag=5ae163c2-f114-4248-b04d-189159a53f43, Authorization=************************************************************************************************************************************************************************************************************************************************************************************************************************ca33a4, X-Amz-Date=20200504T142238Z, x-amzn-apigateway-api-id=iz0blsxnql, X-Amz-Source-Arn=arn:aws:execute-api:us-east-1:<account>:iz0blsxnql/authorizers/rl311v, Accept=application/json, User-Agent=AmazonAPIGateway_iz0blsxnql, X-Amz-Security-Token=IQoJb3JpZ2luX2VjED4aCXVzLWVhc3QtMSJHMEUCIQC1GP3GF2X0xpXcjhtsEudtW6oUCrnd63VlW8TyBVt2TAIgCP9ep6O4UYq37g_rThNfmT9be4MdDuJZjBwyy/iWHT4qtAMIdhAAGgwzOTIyMjA1NzY2NTAiDGCJjHpAAKzdw614eSqRAygH6Z5XxBeGozczYgxcY4Q6T2Dcx9mklFnRHuuvY9u_ATYH3X4fTOwUPveS46oTvfjry_C30qHM9ceFUbANiTgJxv2TYueSusj4h8YOCYJOxMlue5Cn2ZwwPoR_7uZ08Ziu0czFjKpEpYzQjOCGwHN25Pe0JYb6F5fapBIgZsqw [TRUNCATED]
Mon May 04 14:22:38 UTC 2020 : Endpoint request body after transformations: {"type":"TOKEN","methodArn":"arn:aws:execute-api:us-east-1:<account>:iz0blsxnql/ESTestInvoke-stage/GET/","authorizationToken":"tretre"}
Mon May 04 14:22:38 UTC 2020 : Sending request to https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:<account>:function:BearerTokenAuthorizer/invocations
Mon May 04 14:22:38 UTC 2020 : Authorizer result body before parsing: "{"principalId":"tretre","policyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"execute-api:Invoke","Resource":"arn:aws:execute-api:us-east-1:<account>:iz0blsxnql/ESTestInvoke-stage/GET/"}]}}"
Mon May 04 14:22:38 UTC 2020 : Execution failed due to configuration error: Invalid JSON in response: Can not construct instance of com.amazonaws.backplane.executioncore.frontend.authorizer.CustomAuthResponse: no String-argument constructor/factory method to deserialize from String value ('{"principalId":"tretre","policyDocument":{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"execute-api:Invoke","Resource":"arn:aws:execute-api:us-east-1:<account>:iz0blsxnql/ESTestInvoke-stage/GET/"}]}}')
Mon May 04 14:22:38 UTC 2020 : AuthorizerConfigurationException

asked 4 years ago2605 views
1 Answer
1

I sorted it out. When using Ruby for your Lambda custom authorizer, the Ruby SDK implicitly stringifies the response. So, if you take a JSON document and try to convert it to a string, Ruby injects the escape characters for double quotes so your string looks like:

"{ "myjsonkey": "myjsonvalue" }"

This string cannot be parsed by API gateway. Rather than returning your JSON policy from the handler in the form of a string like:

def handler(event, context)

mypolicy = generatePolicy()

JSON.generate(mypolicy)

end

You should instead return the Hash and the Ruby SDK implicitly converts it to JSON. So:

def handler(event, context)
mypolicy = generatePolicy()

mypolicy
end

This is confusing because the lambda instructions all indicate that the body should be a string but in the case of API Gateway, the conversion is done under the covers.

answered 4 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions