403 CloudFront for newly created items

Hello, I am having trouble using the deployed APIs. I am using a custom authorizer, which just allows all actions (for testing purposes). I have created a new item via a POST request. Directly after creating it, I tryed to GET it via it’s UUID. The GET lambda functions reaches out to DynamoDB and grabs the item. If the item was stil not in the database, I would have get a 404 response. But to my surprise, I have got a 403.

After I have executed the GET request 5 minutes later, I have got a 200 back. Can someone explain me this strange behaviour? Running the lambdas locally (serverless-offline) works just as expected - I get the newly created item instantly.

Is this a normal behaviour? Why is there CloudFront in between, if I have not enabled it manually?

It sounds suspiciously like a problem with the custom authorizer because of the status code and 5 minutes being the default TTL to cache custom authorizer results.

You could try checking the Cloud Watch logs to see if your Lambda actually runs. You could also try setting the TTL to 0 so the cache is disabled to see if returns 200 sooner.

Please find attached my authorizer. The code is based on http://docs.aws.amazon.com/apigateway/latest/developerguide/use-custom-authorizer.html Is it possible, that by setting the context.awsRequestId as principalId (instead of some fixed value, like user in the aws example), something gets mixed up? What would be the appropriate usage of the principalId?

async function authorize(event: CustomAuthorizerEvent, context: Context, callback: Callback) {
  var token = event.authorizationToken;
  if (!token) {
    callback(undefined, {
      "statusCode": HttpStatus.UNAUTHORIZED,
      "body": JSON.stringify({ "message": HttpStatus.getStatusText(HttpStatus.UNAUTHORIZED) }),
  } else {
    callback(undefined, generatePolicy(context.awsRequestId, "Allow", event.methodArn));

It’s been a while since I used a custom authorizer so I’m a little rusty here.

The way I’ve always understood custom authorizers is they need to return a policy document with all of the resources the user is allowed to access. By default that policy document is cached against authorization token for 5 minutes.

In your case the first time the custom authorizer is called it grants access to invoke the Lambda handling the POST but not the GET. When you then call the GET it fails because the cached policy says they don’t have access. After 5 minutes when the cache has expired and you attempt to GET it generates a new policy saying you have access to GET but not POST.

Solution 1: Return a policy that allows access to the Lambda’s handling both the POST and GET

Solution 2: Set resultTtlInSeconds: 0 so that the policy document isn’t cached.

1 Like

Thank you very much for such a detailed answer. Solution 1 did the job - I really had to consider, that the policies are cached, such that all policies have to be returned directly, not only for the requested arn.

1 Like