Fab
Fab

Reputation: 1885

getting message: forbidden reply from AWS API gateway

I am trying to create a lambda service on AWS and have it accessed from outside via the API gateway with no authentication or restriction required.

To make things easy I set the gateway for now to be a Mock.

On the Get method of the API, the Authorization is set to None and the API Key is not required.

When I try this, I get {"message":"Forbidden"} (same message if I connect it to the actual lambda service).

Any advice on how to make it accessible?

Upvotes: 149

Views: 241637

Answers (30)

Dmitry Polomoshnov
Dmitry Polomoshnov

Reputation: 5364

I know this question has many answers already, but none worked for me. I checked everything 10+ times and still got 403 "Forbidden" with CW logs saying I'm passing an invalid API key. This was absolutely crazy.

Then I found this: https://repost.aws/questions/QUldESbidUTYC-CKC4cTpLmw/api-gateway-execution-failed-resource-forbidden-due-to-invalid-api-key

The accepted answer there did the trick.

So it turns out that somehow the AWS console tricked me into thinking that my API was associated with api/stage. It showed it correctly visually. But it was still not associated (?).

> aws apigateway get-api-keys

showed that my stageKeys were indeed empty.

And only after I ran

> aws apigateway update-api-key --api-key {KEY_ID} --patch-operations op='add',path='/stages',value='{API_GATEWAY_ID}/{STAGE}'.

everything started to work.

It worked, but without taking usage plans into account.

What I really needed was to call

> aws apigateway update-account --patch-operations op='add',path='/features',value='UsagePlans'

This command migrates deprecated API Gateway account to use usage plans. This is because in our company we started to use API Gateway too long ago for other purposes, and it was still without usage plans feature.

It has created duplicated default usage plans over those I created before, and I needed some cleanup. But then it really started to work as expected.

The AWS console is not aware about this migration (UsagePlans feature on/off) it in any way. It just assumes that this feature is enabled.

That said, there IS a migration guide in the AWS docs, but I ignored it, thinking I didn't need to migrate anything.

Upvotes: 2

The problem for me was the Default endpoint inactive. Once I enabled it, I re-deployed the stage and worked

Upvotes: 0

Sad Tomato Of Joy
Sad Tomato Of Joy

Reputation: 21

In my case, I was using multiple API gateways and API mappings created with SAM. The custom domain was created via terraform. All the REST API gateways worked fine but the one that was HTTP API returned 403 with the message "Forbidden".

Turns out you have to use the Domain name v2 to be able to mix both (see the little note at https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-custom-domain-names.html)

Changing my terraform ressource from aws_api_gateway_domain_name to aws_apigatewayv2_domain_name made it work.

Upvotes: 0

illusionx
illusionx

Reputation: 3895

If Authorization and API KEY Required both are set to true for the method, then make sure you have the following Headers while sending the request:

  1. Content-Type (usually application/x-www-form-urlencoded if GET call)
  2. HOST
  3. X-Amz-Date
  4. Authorization
  5. X-Api-Key

I use POSTMAN for API testing which is quite reliable and then it's preety straight forward.

Note: Do not add X-Api-Key header if you have set API KEY REQUIRED as FALSE. And if you have set AUTHORIZATION as FALSE then do not add Authorization header.

Upvotes: 4

avinashupadhya99
avinashupadhya99

Reputation: 11

In my case, it was a simple mistake while calling the API. I was using curl and I set the header using x-api-key:xxxxxxxxxxx and when I call it with x-api-key: xxxxxxxxxx, it works. A simple space was missing in my case.

Upvotes: 0

Pierre
Pierre

Reputation: 2912

To add to the options to look into:

"Why do I get an HTTP 403 Forbidden error when connecting to my API Gateway APIs from a VPC?"

If you have "private dns" enabled, and you use a VPCEndpoint, you might very well run into this issue. See: Why do I get an HTTP 403 Forbidden error when connecting to my API Gateway APIs from a VPC?

In my case, I had two API Gateways in the same account:

  • a public HTTP API Gateway fronting a Lambda function,
  • a private REST API Gateway fronting a lambda function (with a VPCEndpoint so that my ECS/Fargate containers could talk to the private API)

The problem was that once I set up the private API+VPCEndpoint, it started to siphon all traffic FROM WITHIN AWS to API Gateways (so, both to my public and to my private API Gateways). And that broke the PUBLIC HTTP API.

I banged my head for some time because, from my laptop, I could reach the public API Gateway but NOT from my docker container inside AWS Fargate!

The possible solutions are:

  • Option 1: add a Route53 to the public API if you need to call it from your docker container (that way, your container makes an outbound "internet request" and back into the public gateway [~from outside])
  • Option 2: for the public API, I ended up going for a simpler option: I got rid of the public API and, instead, exposed my Lambda function through an Application Load Balancer: just need to configure the TargetGroup to point to Lambda.

I now have:

  • my Private REST API Gateway (and VPCEndpoint) that fronts the Lambda function for my docker containers (those run in AWS/Fargate in private subnets)
  • my Publicly available ALB to reach the Lambda function (not using HTTP API Gateway anymore for this).

Upvotes: 6

Daniel Jihoon Oh
Daniel Jihoon Oh

Reputation: 1919

If you have set API Key Required option to true, please check below:

  1. You have to pass x-api-key HTTP Header Parameter to AWS API Gateway.
  2. The API Key had to be created.
  3. In addition, you need to check a Usage Plan for the API Key on AWS API Gateway Console.

Upvotes: 137

Linden X. Quan
Linden X. Quan

Reputation: 802

There are many reasons why you get 403. One of reasons is this issue

To sum up the root cause:

When a private DNS is enabled on a VPC endpoint, the API's invoke URL is covered by the private DNS name *.execute-api.us-east-1.amazonaws.com where * is a placeholder for the API ID. When a DNS query is resolved for a public API from inside a VPC, the resolved DNS points to the private IP of the associated VPC endpoint instead of the public IP of the public API. The API call is then routed to the public API through the VPC endpoint instead of routing it through the internet. Because VPC endpoints can route traffic only to private APIs, the result is an HTTP 403 error.

If you are running a lambda within in a VPC that has API Gateway VPC endpoint, then you will get 403. You can run lambda function without VPC

Upvotes: 0

FloofyDoug
FloofyDoug

Reputation: 53

The original question was about the setting the API Keys to "not required". I followed a couple of the steps listed in the answers here, but the main thing I was forgetting to do because I am not familiar with API Gateway was that I had to REDEPLOY the api after I set the API key as "not required".

enter image description here

Upvotes: 0

Rahul Madan
Rahul Madan

Reputation: 11

I faced the same issue I was able to resolve it by adding a "/" at end of the URL

eg. https://xxx52xxxx9.execute-api.eu-central-1.amazonaws.com/dev/hello

gave error {"message":"Forbidden"}

but https://xxx52xxxx9.execute-api.eu-central-1.amazonaws.com/dev/hello/

gave required output

Upvotes: -2

Dave
Dave

Reputation: 36

For me, the issue was that I had API Key Source set to AUTHORIZER in the API Settings but did not have any authorizer defined.

API Key Source

(this was due to my reuse of a CDK construct where this was set

    let restApiConfig: RestApiProps = {
      restApiName: apiName,
      apiKeySourceType: ApiKeySourceType.AUTHORIZER,   // <-- Should be HEADER
      deployOptions: {
        stageName: deployEnv,
...

)

Don't forget to redeploy the API if manually applying the change.

Upvotes: 1

Alex
Alex

Reputation: 1728

My issue was that I was connected to my office's VPN which routes into my company's VPC in AWS. My company had private DNS setup which resulted in the request to the public endpoint being routed to a private IP address belonging to the VPC's interface endpoint for API Gateway.

This article explains it all.

There are 2 solutions:

  1. Turn off VPN when hitting the invoke URL.
  2. Use API Gateway custom domain.

I ended up using solution 1 because I needed to setup a cloudfront in front of API Gateway and the custom domain I want to use was already setup as Edge type with other api gateways associated with it.

For additional reference, Edge type custom domains cannot be set as the origin of another cloudfront because it uses CloudFront to speed up connections across all geographic locations. See this AWS support article for more details.

Upvotes: 3

Shane Rich
Shane Rich

Reputation: 83

I received this error today because the aws_host in the signing header was incorrect (using Boto3 and AWSRequestAuth).

While refactoring I started to loop through multiple requests, but this introduced request was on a different API that required a different aws_host.

auth = AWSRequestsAuth(aws_access_key=credentials.access_key,
                       aws_secret_access_key=credentials.secret_key,
                       aws_token=credentials.token,
                       aws_host=f'api.{env}.XXX.dk',
                       aws_region=region,
                       aws_service='execute-api')

Upvotes: 1

devi
devi

Reputation: 11

I was also facing the same issue a week back and spent sometime to identify the issue. Our api gateway endpoint has been configured to work only through public network and we have a WAF & resource policy to filter the incoming requests to the endpoint. I was able to access the endpoint from a different vpc and not from a particular vpc. I was getting Forbidden error.

At last, found that the vpc that i was trying from, have the VPC Endpoint for the execute api service with private DNS enabled. API Gateway endpoint was resolving to a private IP inside the VPC.

There are two ways to resolve it. One, we can disable the private DNS, which is what I did. It started working very fine after the change. But we have to make sure it doesn't affect others who are using the vpc endpoint.

Two, we can use a custom domain name & we can use that to call from the vpc.

Upvotes: 0

Velu
Velu

Reputation: 1911

This usually comes when we try to access the Private API endpoint with incorrect policy & without passing the 'HOST' header in the invoke request. Let's say I have an API that is deployed as a private endpoint with the below resource policy.

{
"Version": "2012-10-17",
"Statement": [
    {
        "Effect": "Allow",
        "Principal": "*",
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:us-west-2:12345678:2ucqasdfasdfryc/*"
    },
    {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "execute-api:Invoke",
        "Resource": "arn:aws:execute-api:us-west-2:12345678:2dgaucqt6dfgdyc/*",
        "Condition": {
            "StringNotEquals": {
                "aws:SourceVpce": "vpce-87878kjlkj8787k"
            }
        }
    }
]
}

Accessing Private API endpoint when private-DNS-hostnames disabled.

curl -v -H 'Host: 01234567ab.execute-api.us-west-2.amazonaws.com' https://vpce-01234567abcdef012-01234567.execute-api.us-east-1.vpce.amazonaws.com/test/pets

                          

[OR] use the API ID instead of the Host header.

curl -v -H 'x-apigw-api-id: 01234567' https://vpce-01234567abcdef012-01234567.execute-api.us-east-1.vpce.amazonaws.com/test/pets

Upvotes: 1

user3002097
user3002097

Reputation: 183

In my case, it was because I used the

Managed-AllViewer

origin request policy. Switching to

Managed-UserAgentRefererHeaders

solved the problem.

My client sent an Accept-Encoding header, which CloudFront did not like. You can verify this by creating a custom origin request policy of type "Whitelist", and although Accept-Encoding is selectable from the list, you receive an error when creating the policy: "The parameter Headers contains Accept-Encoding that is not allowed."

I did not find the relevant documentation unfortunately. Also no clue why such an inconspicuous header is disallowed.

Upvotes: 6

JakubF
JakubF

Reputation: 11

I had a similar problem. Turned out that my certificate in Certificate Manager was not created in North Virginia region (us-east-1), therefore I could not mark Custom Domain as Edge-optimized. I had to choose Regional instead.

When I re-imported the certificate using N. Virginia region and created a Custom Domain again, but this time with Edge-optimized endpoint configuration, it worked flawlessly.

Upvotes: 1

Leonard Saers
Leonard Saers

Reputation: 663

As @gary69 and @Adriaan Pelzer mentions

https://stackoverflow.com/a/52727654/809043

https://stackoverflow.com/a/55136675/809043

You can get the message {"message":"Forbidden"} when requesting a Private API.

So if you have a setup where all traffic should go thorough a API Endpoint which than directs the traffic to the API Gateway then the following parameters may be used.

APIGatewayVPCEndpoint:
  Type: 'AWS::EC2::VPCEndpoint'
  Properties:
    PolicyDocument: '{
        "Version":"2012-10-17",
        "Statement":[{
          "Effect":"Allow",
          "Principal": "*",
          "Action":["execute-api:Invoke"],
          "Resource":["arn:aws:execute-api:eu-north-1:000000000000:*/*"]
        }]
      }'
  ...
  VpcEndpointType: Interface
  PrivateDnsEnabled: true

If PrivateDnsEnabled is enabled, than the endpoint in the API Gateway needs to be of Type Private, and a policy needs to added.

  ApiGatewayRest:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Description: A mocked API
      Name: Mocked API
      EndpointConfiguration:
        Types:
          - PRIVATE
      Policy: '{
        "Version": "2012-10-17",
        "Statement": [{
          "Effect": "Allow",
          "Principal": "*",
          "Action": "execute-api:Invoke",
          "Resource": "arn:aws:execute-api:eu-north-1:000000000000:*/*/*/*"
        }]
      }'

This forum thread helped clear out some of the details for me

https://forums.aws.amazon.com/thread.jspa?threadID=286760

Upvotes: 0

Quentin Del
Quentin Del

Reputation: 1695

In my case the api key was not enable. Make sure the API is set as Enabled. enter image description here

Upvotes: -1

Dmitriy Popov
Dmitriy Popov

Reputation: 2360

Just a note on the similar case I ran into with Swagger Editor:

  • I exported the OpenAPI 3.0 YAML from API Gateway → Stages → select "Prod" → select "Export" tab → switch radiobutton to "OpenAPI 3" → "Export as OpenAPI 3 + API Gateway Extensions"
  • Paste the received YAML to https://editor.swagger.io/
  • Execute a trivial GET method.
  • It returns 403 Forbidden with {"message":"Forbidden"} body.

curl command from Swagger Editor looked like this:

curl -X GET "https://xxx52xxxx9.execute-api.eu-central-1.amazonaws.com//Prod/users" -H "accept: application/json"

(note the double // before Prod).

And the same curl command without // worked via the command line!

The trick that worked is to replace this server structure returned in the API Gateway-generated:

servers:
  - url: "https://xxx52xxxx9.execute-api.eu-central-1.amazonaws.com/{basePath}"
    variables:
      basePath:
        default: "/Prod"

With the full url without variables:

servers:
  - url: "https://xxx52xxxx9.execute-api.eu-central-1.amazonaws.com/Prod"

Notably, removing the leading slash from default: "/Prod" didn't help.

Upvotes: 2

tgmerritt
tgmerritt

Reputation: 744

The only other reason that I've experienced which I don't see mentioned here is literally that you tried to reach the API too quickly after being published. I hit publish and see the "your API is reachable at" domain name, and immediately copy and pasted that into Postman to check it.

I get the forbidden message. Change nothing. Check all settings to ensure that I haven't done anything - everything is correct. Kinda tearing my hair out.

Return a few minutes later to try because I'm quite sure I'm doing it all correct - it works.

DNS man. No matter how fast the Internet is - it ain't instant :)

Upvotes: 7

Joel
Joel

Reputation: 837

Putting my experience over here as well. I tried all those things above and it turned out that putting the domain with a wildcard solved my {"message":"Forbidden"} issue: *.mydomain.com

Custom domain

Upvotes: 0

haynzz
haynzz

Reputation: 130

I might have come across a solution to this problem. I had the same issue right now on MacOS. I tried to flush my DNS and then it worked!

Try this in the terminal:

Mac OS X Yosemite and later

sudo killall -HUP mDNSResponder

Mac OS X Yosemite v10.10 through v10.10.3

sudo discoveryutil mdnsflushcache

Mac OS X Mavericks, Mountain Lion and Lion

sudo killall -HUP mDNSResponder

Mac OS X Snow Leopard

sudo dscacheutil -flushcache

Upvotes: 2

Adriaan Pelzer
Adriaan Pelzer

Reputation: 1489

I got {"message":"Forbidden"} on an API with EndpointConfiguration set to PRIVATE, and a VpcEndpoint created for it in the Vpc's private subnets (this is an inter-service API)

The reason I got {"message":"Forbidden"} was that I was under the impression I should use one of the VpcEndpoint's urls. The URL to use is still the one associated with the stage (in ApiGateway console). It is:

https://${RestApiId}.execute-api.${Region}.amazonaws.com/${StageName}

Upvotes: 1

Max Lans
Max Lans

Reputation: 31

There are a few things to do when we receive the {message: forbidden} in the API Gateway:

CORS enabled?

  1. Check if CORS is Enabled within the API ( to start with, allow the origin '*', to make sure we can test safely )
  2. Deploy the API to make sure all settings are as expected

API Key enabled?

  1. Check if we have the API Key enabled in the API Gateway
  2. Check if there is an API Key configured.
  3. Check if your API Key is assigned to the correct usageplan and add an API Stage, without the API Stage you will always receive an {message: forbidden}

If you are still facing issues, let me know so me or one of our cloud gurus @levarne can help.

Upvotes: 3

vaquar khan
vaquar khan

Reputation: 11479

You need to deploy your api on stage and use stage url go to Resources, click Actions and choose Deploy API

Now if you are getting error

{"message":"Forbidden"}.

Please check following steps

1 ) If you enable api key copy and pass your key in postman

enter image description here

2) Now you still getting same error means you will need to create usage plan

enter image description here

3) set limit and assign plan to your api

enter image description here

Upvotes: 22

Radu
Radu

Reputation: 2060

Local Firewall / antivirus or NGIPS (Cisco Bluecoat). The latter was my case, where I wouldn't even get logs in CloudWatch from my API. It was allowing my top level domain hosted website, but was blocking with 403 the api subdomain, with no body in the browser's network dev-tools tab.

Upvotes: 1

madhead
madhead

Reputation: 33471

This may be far from obvious, but another reason of seeing "Forbidden" error when using AWS API Gateway may be calling incorrect URL that does not correspond to any deployed API method. It can occur if you're actually hitting wrong URL (e.g. instead of calling https://9999xx9x99.execute-api.us-east-1.amazonaws.com/dev/users (note dev stage before users) you called https://9999xx9x99.execute-api.us-east-1.amazonaws.com/users (no stage). You'd expect to get 404, but you'll get 403.

BTW: after you make a deployement to https://9999xx9x99.execute-api.us-east-1.amazonaws.com/dev/users calling https://9999xx9x99.execute-api.us-east-1.amazonaws.com/user (note singular noun form here) you'll get… 403 as well, but with "Missing Authentication Token" message!

Upvotes: 14

Ignitious Nkwinika
Ignitious Nkwinika

Reputation: 199

I might be too late but one of the reasons API Gateway would give "forbidden" message is when you pass data in request Body on a GET operation. To solve the problem either make your resource POST or you do not pass data in request Body.

Upvotes: 19

Cshah
Cshah

Reputation: 5850

We had faced this issue in our production when we used Kong as our api gateway. Our requests passed thro when initiated from Postman but failed with 403 when initiated via Code. The Bot plugin in Kong was enabled which only allowed requests initiated from Browser or Mobile App based on the user agent header value.Our requests initiated via Http Client failed. Once we disabled the bot plugin then the error didnt occur. It now allows request if the user-agent is Apache-HttpClient/4.5.2 (Java/1.8.0_91).

Upvotes: 0

Related Questions