AWS API Gateway custom Authorizer strange showing error
Asked Answered
G

8

58

Here is the context:

  • I set up a resource in the API gateway. /user/company
  • This resource have 2 methods. Get and POST.
  • I have configured a custom Authorizer for this resource.

The problem:

  • I can call the GET method by sending right authorization information and I get the results as expected.
  • I try to send a POST request and I get the following error:

{
  "message": "User is not authorized to access this resource"
}
  • If I wait for few minutes, then call the POST method, it will work.
  • If after calling the POST method and getting the results I call GET method, it will show the same error as mentioned above.

In addition, I have disabled cache for the authorizer.

enter image description here

What might have caused this issue?

Goree answered 14/5, 2018 at 13:30 Comment(7)
will you be able to print the inputs in the Custom Authorizer (jwtRsaCustomAuthorizer) and check whether those inputs are different between the successful and failing GET/POST requests. Also could you please confirm whether your custom authorizer is stateless (i.e., the implementation stores some values as runtime variables and the authorization logic is depend on those runtime variables)?Precipitate
Thanks for the information, in my custom authorizer, I generated a policy with was for POST, or for GET. When I call any of them first, the policy was generated and for some reason it cached. It would took some minutes to reset and I could call the other method. This happened in spite of setting cache to disable. I tried to generate a policy for the entire API Gateway on each call for a resource and that very well solved the issue.Goree
Policy seems to be cached for a token. During testing I generally create a new token for every request.Adjoining
Have you re-deployed your API after turning off caching?Welt
@Welt I didn't activate caching in the first place. I had a work around to issue the policy for both POST and GET each time I generate a policy.Goree
I'm getting the same error. But in my case, I have given CloudWatchLogs access to the role that is assigned to lambda. So maybe you have some other permission error or might be same permission error I have.Sapid
LIFE SAVER QUESTION 🤣😂Cockhorse
I
44

This could be fixed in two ways that are described in buggy's answer: https://forum.serverless.com/t/rest-api-with-custom-authorizer-how-are-you-dealing-with-authorization-and-policy-cache/3310

Short version:

  1. Set custom authorizer policy resource as "*"
  2. Or (if you are ok with no caching) set TTL for custom authorizer to 0

See the answer by Michael for more details

Imprest answered 1/11, 2018 at 6:24 Comment(2)
setting TTL to 0 did the trick. if anybody's using cf or sam use the ReauthorizeEvery property in the template.Margarethe
This does the trick, but what if do want the caching?Lemuroid
M
56

This error will occur if you use event.methodArn as a resource for generated policy and share an authorizer between different functions, because of how policy caching works. For provided token it caches a policy across an entire API, it will be the same cache entry for all methods and resources within the same API and stage (if they share the same authorizer).

For example, when making a request to GET /users, ARN will look something like this:

arn:aws:execute-api:us-1:abc:123/prod/GET/users

Next call to any endpoint with the same authentication token will use a cached policy, which was created on the first call to GET /users. The problem with that cached policy is that it's resource only allows a single particular resource arn: ... /prod/GET/users, any other resource will be rejected.

Depending on how much do you want to limit policy permissions, you can either mention every possible resource when creating a policy

{
  "principalId": "user",
  "policyDocument": {
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow",
        "Resource": [
          "arn:aws:execute-api:us-1:abc:123/prod/GET/v1/users",
          "arn:aws:execute-api:us-1:abc:123/prod/POST/v1/users",
          "arn:aws:execute-api:us-1:abc:123/prod/GET/v1/orders"
        ]
      }
    ],
    "Version": "2012-10-17"
  }
}

or use wildcards

"Resource": "arn:aws:execute-api:us-1:abc:123/prod/*/v?/*"

or even

"Resource": "*"

You can use policy variables for some advanced templates.

It is also possible to use a blacklist approach by allowing everything using wildcards and then denying specific resources in another policy statement.

Sources:

Mosesmosey answered 13/5, 2019 at 19:50 Comment(5)
I think this should be the best answer. Set TTL to 0 (disable cache) will make authorizers been called whenever your endpoints have been called. This probably not what developers want.Finbur
OOOOMMMMGGGG... YOU ARE THE TRUE LIFE SAVER 😂🤣 Thank you very muchCockhorse
This is a good answer as it describes what the actual issue is.Empiric
Agree with the above : this answer explains what the problem is and how to fix it. Turning off caching without knowing why seems like the wrong approach.Irruptive
Best answer there is! Was stuck with this issue for few days unclear why response was 403 forbidden returned by the Cloudfront and infact requests were not getting propagated to the authorizer or the API gateway.Soredium
I
44

This could be fixed in two ways that are described in buggy's answer: https://forum.serverless.com/t/rest-api-with-custom-authorizer-how-are-you-dealing-with-authorization-and-policy-cache/3310

Short version:

  1. Set custom authorizer policy resource as "*"
  2. Or (if you are ok with no caching) set TTL for custom authorizer to 0

See the answer by Michael for more details

Imprest answered 1/11, 2018 at 6:24 Comment(2)
setting TTL to 0 did the trick. if anybody's using cf or sam use the ReauthorizeEvery property in the template.Margarethe
This does the trick, but what if do want the caching?Lemuroid
L
4

Thanks @Orest for the answer! To set a wildcard on policy resource in the Auth0 custom authorizer, go to lib.js line 57 and change:

.then((decoded)=> ({
        principalId: decoded.sub,
        policyDocument: getPolicyDocument('Allow', params.methodArn),
        context: { scope: decoded.scope }
    }));

by

.then((decoded)=> ({
        principalId: decoded.sub,
        policyDocument: getPolicyDocument('Allow', "*"),
        context: { scope: decoded.scope }
    }));

I hope it will help some...

Lampe answered 11/1, 2022 at 11:21 Comment(0)
N
2

In the your custom policy build code use, the node js module aws-auth-policy The Nodejs part you can use ,

AuthPolicy.prototype.allowAllMethods = function () {
  addMethod.call(this, "allow", "*", "*", null);
}

In the code

const AuthPolicy = require('aws-auth-policy');
  const policy = new AuthPolicy(principalId, awsAccountId, apiOptions);
           // policy.allowMethod(method, resource);
            policy.allowAllMethods();
            const authResponse = policy.build();
Natelson answered 20/3, 2019 at 7:38 Comment(0)
P
1

AWS SAM

For those who are using AWS SAM template + who wants to disable the cache, do these changes in the SAM template. Just add...

ReauthorizeEvery : 0 
            IdentitySource:
              - $request.header.Aut

e.g.

Resources:
  ProjectApi:
    Type: AWS::Serverless::Api
    Properties:
      Auth:
        Authorizers:
          YOURCUSTOMAuthorizer:
            FunctionArn: !GetAtt CUSTOMLAMBDAAUTHORIZER.Arn
            FunctionPayloadType: REQUEST
            Identity:
              Headers:
                - Authorization
              ReauthorizeEvery : 0 -> 'HERE.....'
            IdentitySource:
              - $request.header.Authorization
              - $context.routeKey

Note: API gateway cache should be configured from the template, it wont work from the AWS Console UI.

Pelagic answered 17/11, 2023 at 1:31 Comment(0)
K
0

I fixed this by setting the AuthorizerResultTtlInSeconds to 0.

The reason for this is that I was using a shared authorizer. However the authorizer worked by reading the event context of the request and granting an IAM to then invoke a specific lambda.

Because the authorizer was shared it was caching the response which was an IAM for a specific lambda for the TTL of (in my case) 300 seconds.

Therefore, I could call one API one minute, then not the next.

Changing the value above to 0 fixed the issue.

Kramer answered 1/9, 2019 at 9:54 Comment(0)
A
0

I was facing the same 'User is not authorized to access this resource' my mistake was I did not provided the OAuth Scopes in the Authorizer of my api gateway

Apery answered 30/10, 2020 at 14:35 Comment(0)
A
0

While you are using Lambda Authorizer, the input Key is your Token and response output is something like below:

----
----
"policyDocument": {
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow",
        "Resource": [
          "arn:aws:execute-api:<region>:<account-id>:<api-id>/<stage>/<method>/<resource>"          
        ]
      }
    ]
----
----    

If you cache the lambda authorizer response, it will cached the token as a Key and the lambda response as a value.

Within the configured TTL value time range, if you again hit the API Gateway, it will provide you the same response from the cache. Rather than invoking the Lambda function again.

Base on the response, API Gateway will decide it will allow to access the Resource or not.

If your allowed Resource ARN set doesnt match the your calling APIs ARN, it will return the message "User is not authorized to access this resource".

So, if you want to cache the Authorization to minimize the number of lambda invokation, you should corret your authorizer response using wildcard.

Like bellow, such that cache response also allow other resources.

----
----
"policyDocument": {
    "Statement": [
      {
        "Action": "execute-api:Invoke",
        "Effect": "Allow",
        "Resource": [
          "arn:aws:execute-api:<region>:<account-id>:*/*"          
        ]
      }
    ]
----
----    

Hope it will help to understand the actual issue!!

Afterburning answered 7/4, 2023 at 10:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.