Fixing invalid signatures on the AWS API Gateway

Here are some things I learnt the hard way while working with the API Gateway and trying to authenticate users hitting the API. Something by the way that everyone should be doing! Far too many open end-points out there and the APIG (Amazon API Gateway) gives you IAM control or a shared API KEY. This article is focused on getting IAM working: Another post will cover the details of Cognito/IAM and the APIG.

What goes wrong?

To protect my end-points I wanted to use IAM so that the keys used by the end user would expire every 60 minutes and I’d also know exactly who was using the service. I turned on IAM under the authorization of each of my APIG methods. We’ll assume you have valid AccessKey, SecretKey and SessionTokens obtained via the AWS SDK. I started to run into error messages that all looked something like this:

  • Invalid Signature.
  • The request signature we calculated does not match the signature you provided.
  • The Canonical String for this request should have been ….
  • (You’re using a GET request)
  • Any messages related to invalid tokens, sessions etc are tied to issues around how you authenticated and will be covered elsewhere.

The solution

As of this writing I believe this issue lies within the APIG itself. The gateway is making an assumption that when using GET requests that the body is empty and I mean empty! not {}. If you read over the code in the sigV4Client.js you’ll see that an undefined body also gets changed to {}. When the payload signature is calculated against {} it won’t match the server signature which is being calculated against ”. To fix it change your sigV4Client.js – the method buildCanonicalRequest should read as follows:

function buildCanonicalRequest(method, path, queryParams, headers, payload) {
        if (method == 'GET' || method == 'get') payload = '';
        var result = method + '\n' +
            buildCanonicalUri(path) + '\n' +
            buildCanonicalQueryString(queryParams) + '\n' +
            buildCanonicalHeaders(headers) + '\n' +
            buildCanonicalSignedHeaders(headers) + '\n' +
            return result;

Although you’re allowed by the HTTP specification to pass data in a GET request you really shouldn’t be :) but the {} as a value is acceptable..


I’ve found it is worth sticking it out with these new technologies as I believe this is the direction backend development is going to take, this along with container services such as Docker will quickly replace the typical VM/Instance model of deployment.