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

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.

Related

Is there any way to validate path parameters in AWS API Gateway?

I'm using AWS API Gateway to create an api.
I have the following path for an API: /users/{id}
Is there a way to validate the existence of id in the API request made and maybe its type in API Gateway before it reaches the Lambda integration? I understand API Gateway supports validating request body, query params and headers, but I can't see any option for path parameters, does API Gateway not support that?
I'm going through the documentation and I can't seem to find something clear on that.
API Gateway can check if a path parameter exists or not. It can check if path includes any "id", but it cannot for example check what is it’s regex pattern. Such validation should be made on a client side. Either the API Gateway path follows the defined pattern, in which case it can route you to an appropriate resource, or not. It can however ensure that request parameters are present and non-blank.
The AWS documentation states that API Gateway can perform the basic validation:
API Gateway can perform the basic validation. This enables you, the
API developer, to focus on app-specific deep validation in the
backend. For the basic validation, API Gateway verifies either or both of the following conditions:
The required request parameters in the URI, query string, and headers of an incoming request are included and non-blank.
The applicable request payload adheres to the configured JSON schema request model of the method.
To enable basic validation, you specify validation rules in a request validator, add the validator to the API's map of request validators, and assign the validator to individual API methods.
Note that comparison with JSON schema request model refers to the request payload, and not to request parameters. In the documentation you can find guidance on how to enable request validation in API Gateway:
by importing OpenAPI
definition
using the API Gateway REST
API
using AWS
console
Also, follow this blog post which explains how to set up request parameters validation. Mind however, that the basic validation ensures that the request parameters are present and non-blank. More advanced validation, like checking regex pattern or type, is not possible to my knowledge.

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.

Prevent AWS API Gateway from re-ordering URL parameters?

I'm attempting to port an existing API to AWS API Gateway.
I've got everything working, in that using the 'test' GUI for each of my endpoints successfully hits my configured EC2 instances.
I used the swagger import facility to automatically map all possible endpoints and their associated URL parameters.
What I've noticed is that when the request hits my API (EC2 instance) the URL has been transformed slightly. The URL parameter order has changed.
Regardless of the parameter order that I paste into the test GUI, the order of the parameters when they hit my API has been changed to the order that they are specified within the 'Method Request' GUI screen.
Does anyone know how to prevent this from happening?
There is no way to achieve this using a lambda 'custom authoriser'
I was trying to use a Lambda function as a custom authoriser which then proxies through to our HTTP API. The only data available to the custom authoriser is the 'Token' in the header (can be named anything you want - setup via API Gateway GUI). You can of course populate this with whatever values you want and one suggestion was to put the param order in this header and then perform some logic at this lambda level, however that meant modifying our API callers which wasn't desirable.
You do have access to the 'transformed' URL (e.g. 'https://df64sxl1.execute-api.us-east-2.amazonaws.com/prod/myEndpoint) but this isn't very useful.
If you are able to utilise lambda integration (instead of custom authorisation) you might be able to achieve what you by using payload-template mappings as these provide a way of accessing the raw request.

Using an API key in Amazon API Gateway

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.