I was trying to write a code in Js for GET request via REST API. I am trying to generate signature using the shared key and access key provided by me
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 = "MYACCESSKEY";
secretKey = "my/sharedkey";
region = "us-east-1";
serviceName = "s3";
// 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 = "my_host_name.com";
apiEndpoint="/bucket_name/object_name";
apiQueryString = "";
canonicalHeaders = "host:" apiHost "\nx-amz-date:" amzdate "\n";
//"\nx-amz-security-token:" sessionToken "\n"
signedHeaders = "host;x-amz-date;";
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;
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0
var options = {
method: apiMethod,
host: apiHost,
path: apiEndpoint,
headers: {
'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;
});
console.log("CALLBACK",str);
//the whole response has been recieved, so we just print it out here
response.on('end', function() {
console.log('Complete: ' str);
});
}
console.log(options);
https.request(options, callback).end();
I am getting signature mismatch error.
Complete: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Error><Code>SignatureDoesNotMatch</Code><Resource>archivestorage/objectNameNotDecodedYet</Resource>
<Message>The request signature we calculated does not match the signature you provided. Check your secret access key and signing method.
</Message></Error>
Same header are passed via postman and it is working fine. Can somebody help me out where I am making mistake ? Thanks in advance
CodePudding user response:
It got fixed.
I missed "X-Amz-Content-Sha256" as header.
Once I supplied "X-Amz-Content-Sha256": payloadHash and requested the data, It worked like a charm .
Sharing the code. It will be the first working code that I found in internet.
/** 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 = "MYACCESSKEY";
secretKey = "my/sharedkey";
//sessionToken = "";
region = "us-east-1";
serviceName = "s3";
// 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 = "my_host_name.com";
apiEndpoint="/bucket_name/object_name";
apiQueryString = "";
canonicalHeaders = "host:" apiHost "\nx-amz-date:" amzdate "\n";
//"\nx-amz-security-token:" sessionToken "\n"
signedHeaders = "host;x-amz-date;";
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);
//console.log("BEFORE SIGNATURE:",signingKey);
// Sign the string_to_sign using the signing_key
signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest(
'hex');
//console.log("ALGORITHM",algorithm);
//console.log("SIGNATURE:",signature);
//console.log("X-AMZ-DATE",amzdate);
//console.log("X-AMZ-CRDENTIAL",Credential);
// ************* 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;
//'5e838e45edf32f084705619603ba0acb77961658fedb9a570c771919c9dcf60a';
//console.log("AUTH header ",authorizationHeader);
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0
var options = {
method: apiMethod,
host: apiHost,
path: apiEndpoint,
headers: {
"X-Amz-Content-Sha256": payloadHash,
"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;
});
console.log("CALLBACK",str);
//the whole response has been recieved, so we just print it out here
response.on('end', function() {
console.log('Complete: ' str);
});
}
console.log(options);
https.request(options, callback).end();