Created
May 18, 2017 23:17
-
-
Save jpbarto/2cbc9fc08f0aa6c833c7459f174f6c20 to your computer and use it in GitHub Desktop.
NodeJS SigV4 Invocation of AWS IAM authorized API Gateway endpoint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** 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(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@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.