I am using the below script in preprocessing step in POSTMAN but it is throwing an error
code": 40103,
“message”: “Invalid signature in request credentials”,
“stat”: “FAIL”
“PRE PROCESSING SCRIPT”
function getAuthHeader(httpMethod, requestUrl, requestBody) { console.log(requestBody); //body data console.log(httpMethod); // http type: POST, GET, ETC
var CLIENT_KEY = ‘xxxxxxx’;
var SECRET_KEY = ‘xxxxxxx’;
//var AUTH_TYPE = ‘HMAC-SHA1’;
var moment = require(‘moment’)
//const moment= require(‘moment’);
/* Uncomment out lines below to use your test for getting correct formatted time and date */
var timestamp = moment().format(‘ddd, DD MMM YYYY HH:mm:ss ZZ’);
//var timestamp1 = moment().utcOffset(‘timestamp’);
//var timestamp1 = timestamp.toUTCString();
pm.environment.set(“timestampHeader”,timestamp);
//var timestamp = “Mon, 24 Apr 2023 16:38:18 -0600” ;
//pm.environment.set(“timestampHeader”,timestamp);
var hostname = “■■■■■■■■■■■■■■■■■■■■■■■■”;
var apicall = ‘/admin/v1/users’
var method = ‘POST’
var body = ‘username=xxxx’ //sample username
var requestData = timestamp +‘\n’+method+‘\n’+ hostname +‘\n’+ apicall +‘\n’+ body;
//requestData = requestData.normalize([‘NFC’]);
console.log(requestData);
var hmacDigest = CryptoJS.HmacSHA1(requestData, SECRET_KEY);
console.log(hmacDigest);
var prebase = CLIENT_KEY+“:”+hmacDigest;
console.log(prebase);
var baseComplete = btoa(prebase);
console.log(baseComplete);
var authHeader = "Basic "+baseComplete;
return authHeader;
}
postman.setEnvironmentVariable(‘hmacAuthHeader’, getAuthHeader(request[‘method’], request[‘url’], request[‘data’]));
Headers :
I have seen few similar posts on this script, but no one is clear on how they made it working.
So can someone help on what I am missing in the script and to convert time to UTC?
Hi @Apoorva_Anne ,
You might have already seen this lengthy thread regarding the topic: Preauth API failing but check and ping are good - #14 by testdemo_user
I will paste the pre-request script that I have been using successfully (taken from the above thread). You should only need to replace the ikey, skey and API hostname. Keep the Headers that you already have.
//Tested on Postman for Web Version 10.13.6
function getAuthHeader(httpMethod, requestUrl, requestBody) {
console.log(requestUrl); // Full URL
console.log(httpMethod); // http type: POST, GET, ETC
console.log(requestBody); //POST Body, currently not used
var IKEY = '<ikey>'; //Auth or Admin API IKEY
var SKEY = '<skey>'; //Auth or Admin API SKEY
var API_HOSTNAME = '<api-hostname>'; //Auth or Admin API Hostname
var AUTH_TYPE = 'HMAC-SHA1';
//Adds a ? at the end of the URL even if there aren't any parameters, makes it easier to find the end of the api_call
if (requestUrl.indexOf("?") == -1) {
requestUrl += "?";
}
var paramsStart = requestUrl.indexOf("?");
var hostname_length = API_HOSTNAME.length + 8; //api_hostname + https://
var api_call = requestUrl.slice(hostname_length, paramsStart); //remove hostname and params to get the api_call
console.log(api_call);
var params_unsorted = "";
var params_array = [];
//Create unsorted array of parameters from either URL or Body
//Assuming POST parameters are in the Body, GET paramters are in URL
//(technically it looks like POST can be in the URL as well)
if (Object.keys(requestBody).length !== 0) {
for (var parameter1 in requestBody) {
params_unsorted = parameter1 + "=" + requestBody[parameter1];
params_array.push(params_unsorted);
}
} else {
params_unsorted = requestUrl.substring(paramsStart+1);
params_array = params_unsorted.split("&");
}
console.log(params_array);
params_array.sort(); //lexicographically sort parameters by key
var encoded_params = "";
if (params_array[0] !== ""){ //check if there are any Params to encode and create the string from
var encoded_params_array = params_array.map(urlEncodeParams); //create URL-encoded array of key=value pairs from the sorted array
encoded_params = encoded_params_array.join("&"); //create string of parameters joined by &
}
console.log(encoded_params);
//The current time, formatted as RFC 2822. This must be the same string as the "Date" header (or X-Duo-Date header).
var moment = require('moment');
var timestamp = moment().format("ddd, DD MMM YYYY HH:mm:ss ZZ");
pm.environment.set("timestampHeader",timestamp);
//Then concatenate these components with (line feed) newlines
var requestData = timestamp+"\n"+httpMethod+"\n"+API_HOSTNAME+"\n"+api_call+"\n"+encoded_params;
console.log(requestData);
//compute the HMAC-SHA1 of this canonical representation, using your Duo application's secret key as the HMAC key
var hmacDigest = CryptoJS.HmacSHA1(requestData, SKEY);
console.log(hmacDigest);
//Use HTTP Basic Authentication for the request, using your integration key as the username and the HMAC-SHA1 signature as the password.
var prebase = IKEY+":"+ hmacDigest;
console.log(prebase);
//encodes a string in base-64
var baseComplete = btoa(prebase);
console.log(baseComplete);
var authHeader = "Basic "+ baseComplete;
return authHeader;
}
function urlEncodeParams(value, index, array) {
//split the Key and Value at the first "=", URL-encode the Value, and rejoin them with an "="
//If the separator in the split() is a regular expression that contains capturing parentheses (), matched results are included in the array
return value.split(/=(.+)/)[0] + "=" + encodeURIComponent(value.split(/=(.+)/)[1]);
}
pm.environment.set("hmacAuthHeader", getAuthHeader(request.method, request.url, request.data));
You can then perform the GET
or POST
to the endpoint of your choice (which initially appears to be https://■■■■■■■■■■■■■■■■■■■■■■■■■■■■/admin/v1/users
) in the request field:

Hope this helps!
Hey thanks for the script, Now it worked for me in postman.
1 Like