1

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. see this Can somebody help me out where I am making mistake ? Thanks in advance

sourav_anand
  • 241
  • 1
  • 3
  • 11
  • Does your generated signature match the postman signature? – Jefferey Cave Aug 24 '22 at 22:08
  • @JeffereyCave , it won't match .AWS calcualted signature are dynamic in nature, they will keep changing as we also supply amz-date as arguments which will change with time. – sourav_anand Aug 25 '22 at 09:35
  • I'm expereiencing a similar problem with some code (which is why I ask). Have you considered setting the date to match postman? – Jefferey Cave Aug 25 '22 at 17:11

1 Answers1

2

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();
sourav_anand
  • 241
  • 1
  • 3
  • 11