Home > Mobile >  Unauthorised (401) error while implementing the HMAC authentication in NodeJs
Unauthorised (401) error while implementing the HMAC authentication in NodeJs

Time:11-24

I'm trying to implement an API with HAMC authentication in Nodejs. But always I am receiving an Unauthorised (401) error.

I have followed the below instruction for API implementation:

Authentication

Users will authenticate with the web service using HMAC authentication. The following steps are necessary to authenticate with the web service:

  1. Set the Date header on the HTTP Request to the current UTC date/time expressed in RFC 1123 format (example: Mon, 12 Jan 2015 20:50:07 GMT)

  2. Create a “representation” of the request by concatenating the following values into a single string (in this order, with no separators):

2.1 The request method (GET or POST)

2.2 The full request URI (all lowercase) including any query string parameters

          2.2.1.  Example: https://estimationapi.zirmed.com/1.0/estimate/1234

2.3 The value of the Date header in “yyyy-MM-ddTHH:mm:ss” format (UTC).

2.4 The CustID.

2.5 The Base64 encoded string of the content body (your estimate in the case of a POST).

  1. Compute an HMAC signature by hashing the UTF-8 encoded “representation” with your UTF-8 encoded private WebCallEncryptionKey using HMACSHA256 as the hashing algorithm.

  2. Convert the resultant hash to a Base64 string. This will be the HMAC signature.

  3. Set the Authorization header on the request by concatenating the CustID and HMAC signature separated by a colon. Specify HMACas the authorization scheme.

5.1 Example of an HMAC Authorization header: HMAC 605:pLKb9P8w5e83BMdUH4 m/EeY7O3PsbV5A89KF7IYjnM=

Below is the code I'm using...

const crypto = require("crypto");
const moment = require('moment');
const http = require('http');

let _apiKey = "API_KEY"; // API KEY/HMAC KEY
let _estimateBaseUrl = "http://estimationapi.zirmed.com/1.0";
let _estimateTransaction = "/estimate";
let CustomerID = 'CustomerID'; 

let BaseAddress = new URL(_estimateBaseUrl);
const utcDate = new Date().toUTCString();
let requestDt = utcDate
let RequestContent = "DATA IN JSON"

getEstimate = async (req, res) => {
  let signature = await createRequestAuth(_estimateTransaction, "POST", requestDt, CustomerID, RequestContent);
  let response = await getEstimateID(signature);
  res.send(response);
};

createRequestAuth = async (uriPath, method, requestDate, custId, body = "") => {
  let fullUri = new URL(BaseAddress   uriPath);
  let authHashString = await CreateAuthHashString(method, fullUri.toString().toLowerCase(), requestDate, custId, body);
  let signature = crypto.createHmac('sha256', _apiKey).update(authHashString).digest("base64");
  console.log("signature is === :  ", signature)
  return signature;
}

getEstimateID = (signature) => {
  const data = new TextEncoder().encode( JSON.stringify(RequestContent) );
  const options = {
    hostname: 'estimationapi.zirmed.com',
    port: '',
    path: '/1.0/estimate',
    method: 'POST',
    Headers: {
      Authorization: `HMAC ${CustomerID}:${signature}`,
      Date: requestDt,
      "Content-Type": `application/json`,
      'Content-Length': data.length
    }
  }
  console.log("options ------- ", options);
  const req = http.request(options, res => {
    console.log(`statusCode is:  ${res.statusCode}`)
    console.log(`res is: ${res}`)
    res.on('data', d => { process.stdout.write(d) })
  })
  req.on('error', error => { console.error('error', error) })
  req.write(data)
  req.end()
}

CreateAuthHashString = (method, fullUri, requestDate, custId, body) => {
  let uri = fullUri.toLowerCase();
  let httpMethod = method;
  
  let content = Buffer.from(utf8.encode(body)).toString('base64');
  let authHashString = "".concat("", httpMethod,
    uri,
    moment(requestDate).format('yyyy-MM-DDTHH:mm:ss'),
    custId,
    content
  );
  console.log('authHashString: ', authHashString);
  return authHashString;
}

module.exports = {
  getEstimate
}



Not sure if I have done some silly mistake here but please let me know if anyone is aware of this issue.

CodePudding user response:

2.3 The value of the Date header in “yyyy-MM-ddTHH:mm:ss” format (UTC)

When you use moment(requestDate).format('yyyy-MM-DDTHH:mm:ss'), the formatted value is in local timezone. To format it in UTC, you need to do it as moment(requestDate).utc().format('yyyy-MM-DDTHH:mm:ss').

  • Related