Sylvain
Sylvain

Reputation: 1579

AWS API Gateway returns a 403 with x-amzn-ErrorType:AccessDeniedException header

The context

I have a serverless web app built with AWS trio: API Gateway + Lambda + DynamoDB. The first page of the app send 2 http requests to get data and combine reponses to print the result.

            / APIGateway /projects      => Lambda (DynamoDB request)   \
web app => {                                                            } => display data
            \ APIGateway /organizations => Lambda (Github API request) /

The problem

Every goes fine the first time I ask for the page. But if I try to refresh this page, I get a 403 error on /organizations request. From there, if I wait ~3-5 minutes and I refresh the page again I correctly see all the data and my page is perfectly displayed. Sometimes, the GET /organizations fails, sometimes, it's the GET /projects.

Why I have to wait to be able to correctly refresh the page ? How can I fix it ?

Additional informations

When I have this 403 error, ...

Thanks for your help!

Upvotes: 18

Views: 41686

Answers (1)

Sylvain
Sylvain

Reputation: 1579

The origin of this issue was the custom authorizer which was generating a custom policy for a specific resource. As this policy was cached, when the second request arrives, it doesn't match with the one previously generated and returns an error.

Workaround: Disabling the cache

  • open the AWS console on the API Gateway service,
  • click on your API,
  • select Authorizers in the left pane and select your custom authorizer

In the Result TTL in seconds, type 0 and click Update. Now, you have to deploy your API to publish your changes :

  • click on the Resources menu in the left pane and in the Actions dropdown menu, click Deploy API
  • select the stage and click Deploy

Solution: Improve your policy

def generatePolicy(principalId, context):
  return {
    'principalId': principalId,
    'policyDocument': {
        'Version': '2012-10-17',
        'Statement': [{
            'Action': 'execute-api:Invoke',
            'Effect': 'Allow',
            'Resource': 'arn:aws:execute-api:eu-central-1:123456789012:abcdefghij/prod/*'
        }]
    },
    'context': context
  }

You can be more precise in the Resource property with an array:

'Resource': [
  'arn:aws:execute-api:eu-central-1:123456789012:abcdefghij/prod/GET/projects',
  'arn:aws:execute-api:eu-central-1:123456789012:abcdefghij/prod/GET/user',
  ...
]

You can either Allow a superset of ressources and Deny specific ones.

Have a look on @Jeremiah 's link : https://forums.aws.amazon.com/thread.jspa?threadID=225934&tstart=0

Upvotes: 22

Related Questions