Reputation: 17524
I have a custom authorizer for my Gateway API. I've read many articles on how to customize the error message and code returned to end user when on authentication or authorization errors. This one seemed the most useful.
Problem is the API Gateway doesn't behave as documented.
My custom authorizer implementation (python):
def lambda_handler(event, context):
raise Exception('the sky is falling!')
When I call the API using curl:
kash@Laptop$ date; curl -i -X GET -H "Authorization: Bearer 1234abcd`date +%s`" https://xxxx.execute-api.us-west-2.amazonaws.com/prod/ticket
Mon Jun 4 12:27:51 CDT 2018
HTTP/1.1 500 Internal Server Error
Date: Mon, 04 Jun 2018 17:27:53 GMT
Content-Type: application/json
Content-Length: 16
Connection: keep-alive
x-amzn-RequestId: 9cc6d7ce-681c-xxxx-8a4a-23a7616ba4a5
x-amzn-ErrorType: AuthorizerConfigurationException
x-amz-apigw-id: xxxx=
{"message":null}
kash@Laptop$
How do I make it return HTTP 4xx with {"message": "the sky is falling!"}
?
For debugging: I went to Gateway Responses under my API and updated the "Body Mapping Templates" for "Authorizer Configuration Error (500)" from this:
{"message":$context.error.messageString}
to this:
{
"errorMessage":"$errorMessage",
"messageString":"$messageString",
"context.errorMessage":"$context.errorMessage",
"context.messageString":"$context.messageString",
"context.error.errorMessage":"$context.error.errorMessage",
"context.error.messageString":"$context.error.messageString",
"context.authorizer.error.errorMessage":"$context.authorizer.error.errorMessage"
"context.authorizer.error.errorMessage":"$context.authorizer.error.errorMessage"
"context.authorizer.errorMessage":"$context.authorizer.errorMessage"
"context.authorizer.messageString":"$context.authorizer.messageString"
"type": "$context.error.responseType",
"statusCode": "'404'",
"stage": "$context.stage",
"resourcePath": "$context.resourcePath",
"stageVariables.a": "$stageVariables.a",
"context.apiId": "$context.apiId",
"context.authorizer.claims.property": "$context.authorizer.claims.property",
"context.authorizer.principalId": "$context.authorizer.principalId",
"context.authorizer.property": "$context.authorizer.property",
"context.httpMethod": "$context.httpMethod",
"context.error.message": "$context.error.message",
"context.error.messageString": "$context.error.messageString",
"context.error.responseType": "$context.error.responseType",
"context.extendedRequestId": "$context.extendedRequestId",
"context.identity.accountId": "$context.identity.accountId",
"context.identity.apiKey": "$context.identity.apiKey",
"context.identity.apiKeyId": "$context.identity.apiKeyId",
"context.identity.caller": "$context.identity.caller",
"context.identity.cognitoAuthenticationProvider": "$context.identity.cognitoAuthenticationProvider",
"context.identity.cognitoAuthenticationType": "$context.identity.cognitoAuthenticationType",
"context.identity.cognitoIdentityId": "$context.identity.cognitoIdentityId",
"context.identity.cognitoIdentityPoolId": "$context.identity.cognitoIdentityPoolId",
"context.identity.sourceIp": "$context.identity.sourceIp",
"context.identity.user": "$context.identity.user",
"context.identity.userAgent": "$context.identity.userAgent",
"context.identity.userArn": "$context.identity.userArn",
"context.integrationLatency": "$context.integrationLatency",
"context.path": "$context.path",
"context.protocol": "$context.protocol",
"context.requestId": "$context.requestId",
"context.requestTime": "$context.requestTime",
"context.requestTimeEpoch": "$context.requestTimeEpoch",
"context.resourceId": "$context.resourceId",
"context.resourcePath": "$context.resourcePath",
"context.responseLength": "$context.responseLength",
"context.responseLatency": "$context.responseLatency",
"context.status": "$context.status",
"context.stage": "$context.stage"
}
and the response is:
{
"errorMessage":"",
"messageString":"",
"context.errorMessage":"",
"context.messageString":"",
"context.error.errorMessage":"",
"context.error.messageString":"null",
"context.authorizer.error.errorMessage":""
"context.authorizer.error.errorMessage":""
"context.authorizer.errorMessage":""
"context.authorizer.messageString":""
"type": "AUTHORIZER_CONFIGURATION_ERROR",
"statusCode": "'404'",
"stage": "prod",
"resourcePath": "/ticket",
"stageVariables.a": "",
"context.apiId": "xxxx",
"context.authorizer.claims.property": "",
"context.authorizer.principalId": "",
"context.authorizer.property": "",
"context.httpMethod": "GET",
"context.error.message": "",
"context.error.messageString": "null",
"context.error.responseType": "AUTHORIZER_CONFIGURATION_ERROR",
"context.extendedRequestId": "xxxx=",
"context.identity.accountId": "",
"context.identity.apiKey": "",
"context.identity.apiKeyId": "",
"context.identity.caller": "",
"context.identity.cognitoAuthenticationProvider": "",
"context.identity.cognitoAuthenticationType": "",
"context.identity.cognitoIdentityId": "",
"context.identity.cognitoIdentityPoolId": "",
"context.identity.sourceIp": "xxx.244.xxx.2",
"context.identity.user": "",
"context.identity.userAgent": "curl/7.47.0",
"context.identity.userArn": "",
"context.integrationLatency": "",
"context.path": "/prod/ticket",
"context.protocol": "HTTP/1.1",
"context.requestId": "57e2462d-681c-xxxx-7dd93186dc68",
"context.requestTime": "04/Jun/2018:17:25:57 +0000",
"context.requestTimeEpoch": "1528133157762",
"context.resourceId": "pz9fb8",
"context.resourcePath": "/ticket",
"context.responseLength": "",
"context.responseLatency": "",
"context.status": "",
"context.stage": "prod"
}
I've read:
and some more on AWS forums.
Upvotes: 10
Views: 13111
Reputation: 17524
In case it helps someone:
CA = custom authorizer
Other unrelated thing: Because the CA throws an exception in certain conditions to convey auth failure, from a metric point of view this increments the Lambda ErrorCount metric. So that metric isn't reliable to identify "application errors".
Upvotes: 27
Reputation: 2194
the mapping of authorizer and gateway response is done through
https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html
you can change the return status code there to customize the status code.
As to error message, i just tried adding a field to my context output by authorizer, as documented here, https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
and referring to that field in my template mapping for access_denied as $context.authorizer.myErrorMsg
and it works if my authorizer outputs a deny policy document.
Hope it helps
Upvotes: 3