Skip to content

Instantly share code, notes, and snippets.

@jpbarto
Created May 18, 2017 23:17
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpbarto/2cbc9fc08f0aa6c833c7459f174f6c20 to your computer and use it in GitHub Desktop.
Save jpbarto/2cbc9fc08f0aa6c833c7459f174f6c20 to your computer and use it in GitHub Desktop.
NodeJS SigV4 Invocation of AWS IAM authorized API Gateway endpoint
/** The following is a NodeJS port of the AWS SigV4 signing sample code (Python) to NodeJS
* The addition of the Authorization header has been informed by the use of Postman
* For more information see the following documentation:
* http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
*/
var https = require('https');
var crypto = require('crypto');
function sign(key, message) {
return crypto.createHmac('sha256', key).update(message).digest();
}
function getSignatureKey(key, dateStamp, regionName, serviceName) {
kDate = sign('AWS4' + key, dateStamp);
kRegion = sign(kDate, regionName)
kService = sign(kRegion, serviceName);
kSigning = sign(kService, 'aws4_request');
return kSigning;
}
// values retrieved from Cognito Federation
accessKey = "YOURACCESSKEY";
secretKey = "YourSecretKey";
sessionToken = "YourCognitoFederatedIdentitySessionToken";
region = "eu-west-2";
serviceName = "execute-api";
// ex 20180518T210317Z
var now = new Date();
amzdate = now.toJSON().replace(/[-:]/g, "").replace(/\.[0-9]*/, "");
datestamp = now.toJSON().replace(/-/g, "").replace(/T.*/, "");
// prepare to send an HTTP request to https://your-api-gateway.execute-api.eu-west-2.amazonaws.com/stage/secure/endpoint
apiMethod = "GET";
apiHost = "your-api-gateway.execute-api.eu-west-2.amazonaws.com";
apiEndpoint = "/stage/secure/endpoint";
apiQueryString = "";
canonicalHeaders = "host:" + apiHost + "\nx-amz-date:" + amzdate +
"\nx-amz-security-token:" + sessionToken + "\n"
signedHeaders = "host;x-amz-date;x-amz-security-token";
payloadHash = crypto.createHash('sha256').update('').digest('hex');
canonicalRequest = apiMethod + "\n" + apiEndpoint + "\n" + apiQueryString +
"\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + payloadHash;
console.log('preparing to invoke canonical request:');
console.log(canonicalRequest);
// ************* TASK 2: CREATE THE STRING TO SIGN*************
// Match the algorithm to the hashing algorithm you use, either SHA-1 or
// SHA-256 (recommended)
algorithm = 'AWS4-HMAC-SHA256';
credentialScope = datestamp + '/' + region + '/' + serviceName + '/' +
'aws4_request';
stringToSign = algorithm + '\n' + amzdate + '\n' + credentialScope + '\n' +
crypto.createHash('sha256').update(canonicalRequest).digest('hex');
// ************* TASK 3: CALCULATE THE SIGNATURE *************
// Create the signing key using the function defined above.
signingKey = getSignatureKey(secretKey, datestamp, region, serviceName);
// Sign the string_to_sign using the signing_key
signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest(
'hex');
// ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
// The signing information can be either in a query string value or in
// a header named Authorization. This code shows how to use a header.
// Create authorization header and add to request headers
authorizationHeader = algorithm + ' ' + 'Credential=' + accessKey + '/' +
credentialScope + ', ' + 'SignedHeaders=' + signedHeaders + ', ' +
'Signature=' + signature;
var options = {
method: apiMethod,
host: apiHost,
path: apiEndpoint,
headers: {
'X-Amz-Security-Token': sessionToken,
'X-Amz-Date': amzdate,
'Authorization': authorizationHeader
}
};
callback = function(response) {
var str = '';
//another chunk of data has been recieved, so append it to `str`
response.on('data', function(chunk) {
str += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function() {
console.log('Complete: ' + str);
});
}
https.request(options, callback).end();
@akashsharma88
Copy link

How can i post data , I tried like
var req = https.request(options, callback); req.write(JSON.stringify({"name":"akash"})); req.end()
but it does not work , It always shows The request signature we calculated does not match the signature you provided.,
can you help me on how to post data with signed request

@gabrieleCutowl
Copy link

@akashsharma88 I face the same problem and in my case was the querystring parameters order...

I follow the official docs: https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html

I know a lot of time is passed, but I hope it will be helpful for somebody.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment