Using an API key in Amazon API Gateway - amazon-web-services

I have created an API Key and added it to my functions. I have then deployed the api and tested it but still get:
"message": "Forbidden"
How do I pass the api key with my JSON request as I have been using "x-api-key": "theKey"?

The x-api-key parameter is passed as a HTTP header parameter (i.e. it is not added to the JSON body). How you pass HTTP headers depend on the HTTP client you use.
For example, if you use curl and assuming that you POST the JSON payload, a request would look something like (where you replace [api-id] with the actual id and [region] with the AWS region of your API):
$ curl -X POST -H "x-api-key: theKey" -H "Content-Type: application/json" -d '{"key":"val"}' https://[api-id].execute-api.[region].amazonaws.com

I had to add an API Usage plan, and then link the plan to the API stage.
Seems like this is the only way to link the key to the API, not sure if this is a recent change on AWS.

If you set 'API Key Required' option to true, please check below.
you have to pass 'x-api-key' HTTP Header Parameter to API Gateway.
The API Key had to be created.
In addition, you need to check a Usage Plan for the API Key on API Gateway Console.

If you set 'API' key required to true, you need to pass the api key as header.
API Key is passed as header field 'x-api-key'. Even after adding this field in header, this issue may occur. In that case, please validate below points
Do you have a Usage Plan? if not need to create one.
Link you API with Usage Plan. For that add a stage, it will link your API
Do you have API Key? if not you need to create an API Key and enable it.
Add the Usage Plan which is linked with your API to this API Key. For that, add Usage Plan.

I hope you are not missing to link the API key with the API

I was able to get a successful response from Lambda using below configuration in Postman native app -
Under authorization tab (For some reason this didn't work when i passed the same parameters under header)
Key : x-api-key
Value : your-api-key-value
Add to : Header

I don't have enough reputation to set this as a comment, But I was finally able to find the document specifying that 'x-api-key' belongs in the header for API Gateway calls that come from outside clients (like postman, swagger, etc.) in the AWS Documentation.
The relevant part:
To use header-sourced API keys:
Create an API with desired API methods. And deploy the API to a
stage.
Create a new usage plan or choose an existing one. Add the deployed
API stage to the usage plan. Attach an API key to the usage plan or
choose an existing API key in the plan. Note the chosen API key
value.
Set up API methods to require an API key.
Redeploy the API to the same stage. If you deploy the API to a new
stage, make sure to update the usage plan to attach the new API
stage.
The client can now call the API methods while supplying the x-api-key
header with the chosen API key as the header value.
Choose an API key source

For Private API Gateways accessed through public DNS, we need to pass additional header of 'x-apigw-api-id' with the api id along with 'x-api-key' if configured.
curl -v https://{vpce-id}.execute-api.{region}.vpce.amazonaws.com/test -H 'x-apigw-api-id:{api-id}'
Its documented below,
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-api-test-invoke-url.html#w20aac13c16c28c11

Here a good resource explaining different reasons why we could be getting a Forbidden. The two most important are the request URL and the x-api-key header:
https://{api_id}.execute-api.{region}.amazonaws.com/{stage_name}/{resource_name}
Missing stage name will give you 403 for ex. Maybe for security reasons the response is not revealing an issue with the stage name, and thus you get a generic Forbidden.

I faced the same problem today. I had already mapped the API key to the usage plan (which was linked to the api gateway stage). I was also passing the api key in header correctly.
When none of these solutions work, do remember to check if your API is linked to WAF policy with only a certain ip-addresses permitted. Apparently, my IP address had changed today. So, WAF was blocking me. That can be an additional reason to get {"message": "Forbidden"} error.

Related

In AWS how do I add an API key to my API?

Hello: I've been following two tutorials in the AWS documentation:
creating the sample pet store API (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-from-example.html)
...and creating an API key (https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-setup-api-key-with-console.html#api-gateway-usage-plan-create-apikey).
When I test the pet store get method with the provided URL, it returns:
Welcome to your Pet Store API You have successfully deployed your
first API. You are seeing this HTML page because the GET method to the
root resource of your API returns this content as a Mock integration.
The Pet Store API contains the /pets and /pets/{petId} resources. By
making a GET request to /pets you can retrieve a list of Pets in your
API. If you are looking for a specific pet, for example the pet with
ID 1, you can make a GET request to /pets/1.
You can use a REST client such as Postman to test the POST methods in
your API to create a new pet. Use the sample body below to send the
POST request:
{
"type" : "cat",
"price" : 123.11 }
Now I go to the API Gateway -> API -> Resources -> -> Method Request -> API Key Required and change it to "True" and redeploy.
When I go to the provided URL to test, now the page returns:
{"message":"Forbidden"}
Which makes sense... I told it API required = true, right?
So my question is, how do I pass the API key? So that I don't get the "forbidden" result? I didn't see that in the tutorial links I pasted above and haven't been able to find elsewhere.
You Create a Usage Plans
Attach this usage plan to your API and Stage
Create an API Key
Now invoke your API with header named x-api-key and value of it is the API Key created in step-3
Sample:
curl -i -H "x-api-key: Cd2YiWs8Fv8Lg6njI0wXf1iiNOE94XjM3EQe8567" -X GET https://7r9cvghbf4.execute-api.ap-northeast-2.amazonaws.com/dd/pets
Assuming you've followed all steps for creating the API key you can use this API key by specifying it in the x-api-key header within your request.
You distribute API keys to your customers and require them to pass the API key as the X-API-Key header of each incoming request.
More information for using API keys in API Gateway is available on: Choose an API key source - Amazon API Gateway

AWS API Gateway Get Method How to Pass API Key?

I have a working AWS API Gateway GET method. I want to secure it using an API key, so I've created an API key and usage plan, etc.
So previously when I wanted to call the GET method, I would just type a URL with the appropriate parameters into the browser and send it. However, now that we've introduced the API key into the mix, I'm not sure how to call it.
I'm aware of the command line GET and curl tools. Which of these 3 tools (browser, GET, CURL) can accomplish this task and what syntax do I need to use to make the request to the GET method passing the API key?
Mark B is right, I'm just copying because it's the right answer.
You must pass an HTTP header named x-api-key with the API Key as the value. One tool is cURL, another is Postman.

Missing Authentication Token while accessing API Gateway?

I am trying to call a Lambda Function through AWS API Gateway.
When I mention Authentication type NONE it works fine but API become public and anyone with url can access my API.
To make API call secure, I am using Authentication type AWS_IAM and
also attached AmazonAPIGatewayInvokeFullAccess policy to my user but getting this error:
{ message: "Missing Authentication Token"}
I don't know what I am missing here.
I've lost some time for a silly reason:
When you create a stage, the link displayed does not contain the resource part of the URL:
API URL:
https://1111.execute-api.us-east-1.amazonaws.com/dev
API + RESOURCE URL
https://1111.execute-api.us-east-1.amazonaws.com/dev/get-list
The /get-list was missing
And of course, you need to check that the method configuration looks like this:
I think you are directly trying to access API link, this won't work because API is secured using IAM role and you must provide AWS authentication i.e Access key and Secret key.
Use the Postman Chrome extension to test your API:
http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html
I just had the same issue and it seems it also shows this message if the resource cannot be found.
In my case I had updated the API, but forgotten to redeploy. The issue was resolved after deploying the updated API to my stage.
Make sure you are clicking on the specific Resource first in the Stages tree, as that will populate a URL with the full path to the resource (rather than just the root path):
For other causes, see http://www.awslessons.com/2017/aws-api-gateway-missing-authentication-token/
Looks like (as of April 2019) AWS API Gateway throws this exception for a variety of reasons - mostly when you are hitting an endpoint that API Gateway is not able to reach, either because it is not deployed, or also in cases where that particular HTTP method is not supported.
I wish the gateway sends more appropriate error codes like HTTP 405 Method not supported or HTTP 404 not found, instead of a generic HTTP 403 Forbidden.
Found this in the docs:
If the AWS_IAM authorization were used, you would sign the request using the Signature Version 4 protocols.
Signing request with Signature Version 4
You can also generate an SDK for your API.
How to generate an SDK for an API in API Gateway
Once you've generated the SDK for the platform of your choice, step 6 mentions that if you're using AWS credentials, the request to the API will be signed:
To initialize the API Gateway-generated SDK with AWS credentials, use code similar to the following. If you use AWS credentials, all requests to the API will be signed. This means you must set the appropriate CORS Accept headers for each request:
var apigClient = apigClientFactory.newClient({
accessKey: 'ACCESS_KEY',
secretKey: 'SECRET_KEY',
});
I try all the above, if you did all steps in the above answers, and you not solve the problem, then:
on the left menu, hit the "Resources"
in the right to "Resources", hit the api method that you want to test, like "POST/GET etc)
hit the "ACTION" list (it's above to the API method in step 2
select "DEPLOY API" (please do it, even you already deploy yours api)
in "deployment stage" select "prod" or what ever you write in yours previous deploy (it will override yours previous deploy
hit deploy
I thing that because of, when I create the "METHOD REQUEST" (see step 2 how to go to this menu) , in "Authorization" I select "AWS_IAM"
after testing api, in aws test option, I try it in "postman"
then I understand the in "METHOD REQUEST" , in "Authorization", I should select "none"
I change it to none, but I thing the AWS, need to deploy it again, as I explain
Make sure you create Resource and then create method inside it. That was the issue for me. Thanks
In my case I missed adding '/' forward slash at the end of api.
Such a silly mistake.
https://le9dq5l9.execute-api.eu-west-1.amazonaws.com/v1/putdoctorinfo/
If you enable AWS_IAM authentication you must sign your request with AWS credentials using AWS Signature Version 4.
Note: signing into the AWS console does not automatically sign your browser's requests to your API.
sometimes this message shown when you are calling a wrong api
check your api endpoint
In my case it was quite a stupid thing.
I've get used that new entities are created using POST and it was failing with "Missing Authentication Token". I've missed that for some reason it was defined as PUT which is working fine.
This error mostly come when you call wrong api end point.
Check your api end point that you are calling and verify this on api gateway.
If you are using an API with endpoint of type PRIVATE, be sure of:
You are invoking the API from within your AWS account (example: from an EC2 instance created in your account)
Put necessary credential (access and secret keys) in the EC2 instance in route ~/.aws/credentials (this route is for linux instances) If IAM user use MFA aws_session_token value will be required too.
Use vpce (vpc endpoint) based URL. Example: curl https://vpce-0c0471b7test-jkznizi5.execute-api.us-east-1.vpce.amazonaws.com/dev/api/v1/status
Your EC2 instance have a security group than allow outbound traffic to another security group owned by the vpce like:
Your vpce security group allow inbound traffic from another security group (previous sg from ec2 instance) owned by the EC2 instance like:
See: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-private-apis.html
I had the same problem which I solved the following way:
GET Method test
https://54wtstq8d2.execute-api.ap-southeast-2.amazonaws.com/dev/echo/hello
Authorization tab ->
• select type(AWS signature)
• Add AccessKey and SecretKey
You must be using Invoke Url to trigger Lambda Function from your browser or POSTMAN... Instead, use the API end point which will be listed in:
select yourLambdaFuntion >> Configuration >> Triggers.
There you can see API end point.
For the record, if you wouldn't be using credentials, this error also shows when you are setting the request validator in your POST/PUT method to "validate body, query string parameters and HEADERS", or the other option "validate query string parameters and HEADERS"....in that case it will look for the credentials on the header and reject the request. To sum it up, if you don't intend to send credentials and want to keep it open you should not set that option in request validator(set it to either NONE or to validate body)
I had the same issue, and fixed it by removing the /dev/ and just put: https://1111.execute-api.us-east-1.amazonaws.com/get-list
I had same issue today because I was using GET instead of POST. Fixed the issues by changing method to POST in postman.
First of all, check whether the API you created in the lamda function is registered with your AWS project or not. For that, go to the API gateway in your AWS console. If it is not registered, register it. This is the main cause of this issue.
You can even see in your aws.export.js file, that there are paths corresponding to your API ['/items'].
Your API must be present there, otherwise it will not append the security token to requests. Just register it in your project cloud-logic in your console for this.
If it's there, then use the above mentioned solution
http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html
To contribute:
I had a similar error because my return response did not contain the 'body' like this:
return {
'statusCode': 200,
'body': "must contain the body tag if you replace it won't work"
}
If you set up an IAM role for your server that has the AmazonAPIGatewayInvokeFullAccess permission, you still need to pass headers on each request. You can do this in python with the aws-requests-auth library like so:
import requests
from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
auth = BotoAWSRequestsAuth(
aws_host="API_ID.execute-api.us-east-1.amazonaws.com",
aws_region="us-east-1",
aws_service="execute-api"
)
response = requests.get("https://API_ID.execute-api.us-east-1.amazonaws.com/STAGE/RESOURCE", auth=auth)
Well for anyone still having the problem and I really feel very dumb after realizing this, but I passed in the url of /items the default one while adding API. But I kept calling the endpoint with /api. Special thanks to Carlos Alberto Schneider, as I realized my problem after reading your post.
According to my experience, please check the following steps:
On API gateway side, make sure you add the correct path and publish the resource at the stage you want. For some url pattern like path parameter(/user/{user_id}) need more attention to have a check.
Make sure you configure the correct options method for this resource, because sometimes it is the CORS that cause this problem.
On Lambda side, make sure you specify the correct handler name as the entrypoint.
Please always check cloudwatch logs of your lambda that can help u identify the problems on your lambda side.
In my case I was trying to do an UPDATE type request but in my AWS SAM template I had a PATCH type request:
Resources:
LambdaFunction:
Type: AWS::Serverless::Function # More info about Function Resource:
# https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: src/
Handler: app.lambda_handler
Runtime: python3.8
MemorySize: 128
Events:
UpdateItem:
Type: Api
Properties:
Path: /my-endpoint
Method: patch
Things to check:
1. In resources, check for Authorization and API Key if these are required.
2. Redeploy the API, new changes might not reflected.
3. Get the url from stages, directly by clicking on the actions like GET, POST, These will contain the full path urls.
I had the same issue even if my access was regional and not private, no authorization on my method neither API. It's turned out that I was calling the root endpoint "https://azerty.execute-api.eu-west-3.amazonaws.com/dev/", which in local return me a json but raised an error. Be sure to call a proper endpoint, such as "https://azerty.execute-api.eu-west-3.amazonaws.com/dev/hello"

API Key enabled, but requests without key still running

In my API Gateway console, I did the following:
Created an API key
Associated the key with a deployed API stage
Checked the key's "Enabled" checkbox
For each method of each resource of my API, required the API key for authentication
I expected curl https://my-api-gateway-url/my-resource to 403, since I didn't include the x-api-key header, but it was a 200 instead. My Lambda function behind API Gateway ended up running when it shouldn't have run without the API key.
How can I ensure the key is required to authenticate all requests?
EDIT: I was following the documentation here: http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-api-keys.html
Just answered my own question. Posting my answer here as I know I'm not the only one wondering about this, like this person.
The answer is to redeploy your API. Although redeploying sounds obvious, the docs completely skip the vital last step, so it's easy to overlook.

When using Amazon API Gateway, how do I get the API key used in the request from a Django backend?

Pretty self explanatory title. I'm using API Gateway in AWS, requiring an API key to access a backend written in Django (not using lambda). I need to know how to access the API key used in the request to keep track of who did what at the app level.
You can use mapping templates and get the API Key from the $context variable, it’s the apiKey property inside the identity object: http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference
Create a mapping template for your requests and include the property in it. For example, if you wanted to include the entire request body + the API Key you would do this:
{
"body": $input.json('$'),
"apiKey": "$context.identity.apiKey"
}
Depending on how your backend application is built, you could send the API key to your application in a HTTP parameter (path, query string, or header) or in the request body. Please have a read through the docs on how to move data between the two systems.
Thanks,
Ryan
Here is how I finally made it work. At the top or bottom of the template, include this line.
#set($context.requestOverride.header.x-api-key = $context.identity.apiKey)
When your backend receives this request, the api key will be in the header x-api-key.
Here is a basic mapping template that just forwards the (json) body and the header.
$input.json("$")
#set($context.requestOverride.header.x-api-key = $context.identity.apiKey)
API Gateway uses the X-API-Key header, so I like for my backend to also use that. That way I can use the same testing commands with only the URL being different.