How to setup API keys for AWS API Gateway using SAM template
Mon, 30 Sep 2019

At first you could think it is pretty simple, however it is not. Once again AWS documentation is a bit incomplete. Therefore I decided to write a quick guide to save you a couple of hours of desperation and depression.

So first problem, as today, 2019-09-29, SAM does not support API keys directly. Therefore one alternative is to use swagger definition securityDefinitions and

x-amazon-apigateway-api-key-source 
The second problem is that you cannot use an API key alone, it must be associated with an API usage plan.

In our swagger definition we should add the following lines of code:

x-amazon-apigateway-api-key-source: HEADER
securityDefinitions:
  MyApiKey:
    type: "apiKey"
    name: "x-api-key"
    in: "header"
paths:
  your/path:
    get:
      security:
        - MyApiKey: []

Now let's create our API key directly from our template:

MyApiKey:
  Type: AWS::ApiGateway::ApiKey
  Properties:
    Enabled: true

After finish, you should deploy your application, for the purpose of automation I have created a simple script to deploy any template (Cloudformation or SAM) directly from the command line. After deploying let's test our end point without authentication.

curl -X GET https://my-endpoint

Execute the command and, hopefully, you should receive this message: {"message":"Forbidden"} . Now let's try with the API key. To grab it, just log into the AWS console and navigate to API Gateway, then click on "API keys", select your key and under "API key" click on show. Copy it and paste it on the following script.

curl --header "x-api-key: <your api key>" -X GET https://my-endpoint

The key must be placed on the x-api-key header. Execute the script and you should receive this message: {"message":"Forbidden"}

Wait what?! Yes, this is an expected behavior and it took me some research to finally get an answer. So what is going on here? Well, when you setup an API key, you must also associate it with a usage plan. So let us create a plan with SAM template by adding two more resources: the first is the plan itself, the second is the association with the API key that we previously created.

APIUsagePlan:
  Type: AWS::ApiGateway::UsagePlan    
  Properties:
   ApiStages:
    - ApiId: !Ref MyApi
      Stage: !Ref Environment

ApiUsagePlanKey:
  Type: AWS::ApiGateway::UsagePlanKey
  Properties:
    KeyId:!Ref MyApiKey
    KeyType: API_KEY
    UsagePlanId: !Ref APIUsagePlan

Now let's deploy again and test it. Finally this time the response should be 200. I really hope I saved you couple of hours of work by writing this post. If you have any comments or suggestions, feel free to contact me at [email protected] or visit my site.

Cheers!


Thanks for reading!