Here’s my pre-request script. I have configured this at a collection level and then all requests inherit it to avoid having to repeat myself.
You need to set the Authorization
to type API key
:
Then paste this into the Pre-request script
section :
const ts = Date.now();
pm.environment.set("timestamp", ts);
const apiSecret = pm.environment.get("API_SECRET");
sign(getBodyPayload());
function getBodyPayload()
{
const paramsObject = new Map()
const parseParam = (param) => {
if (param.key != 'signature' &&
param.key != 'timestamp' &&
!is_empty(param.value) &&
!is_disabled(param.disabled))
{
//console.log({key: `${param.key}`, value: `${encodeURIComponent(param.value)}`});
paramsObject.set(param.key, encodeURIComponent(pm.variables.replaceIn(param.value)));
//pm.environment.set(param.key, encodeURIComponent(param.value));
}
};
// go through query parameters
console.log(`Query string: ${pm.request.url.query}`);
pm.request.url.query.map(parseParam);
// go through body payloads.
if(pm.request.body.mode == "urlencoded") {
console.log(`Body payload: ${pm.request.body.urlencoded}`)
pm.request.body.urlencoded.each(parseParam);
}
// Must come last -- order is important.
paramsObject.set('timestamp', ts);
return paramsObject
}
function sign(payload)
{
console.log(`Populated params: ${payload.size}`);
//paramsObject.forEach((d) => console.log(d));
let signature = null;
if (apiSecret) {
let queryString = "";
payload.forEach((value, key) => queryString += (key + "=" + value + "&") );
queryString = queryString.substring(0,queryString.length - 1);
console.log(`Singing query string: ${queryString}`);
signature = CryptoJS.HmacSHA256(queryString, apiSecret).toString();
console.log(`Generated signature: ${signature}`);
pm.environment.set("signature", signature);
payload.set("signature", signature)
} else {
console.warn("No API SECRET found!");
}
return signature;
}
function is_disabled(str) { return str == true; }
function is_empty(str) {
if (typeof str == 'undefined' ||
!str ||
str.length === 0 ||
str === "" ||
!/[^\\s]/.test(str) ||
/^\\s*$/.test(str) ||
str.replace(/\\s/g, "") === "")
{
return true;
}
else
{
return false;
}
}
function queryStringToObject(queryString) {
let obj = {}
if(queryString) {
console.log(queryString);
queryString.split('&').map((item) => {
const [ k, v ] = item.split('=')
v ? obj[k] = v : null
})
}
return obj
}
Once you have this you need to configure your environment settings
with the following variables (some of these are empty placeholders that are auto-populated during the pre-script execution):
Finally in the request settings:
You should also setup the Authorization
to Inherit from parent
.
This would then work for any request. The only rules are:
-
recvWindow
parameter needs to be before timestamp
.
-
timestamp
parameter needs to be before signature
.
-
signature
parameter must ALWAYS be the last parameter (as shown in the screenshot)
The code you posted looks okay to me, but I don’t know what the payload is (I am assuming it’s just timestamp=unix timestamp with millis
(check this or use new Date().now()
in your js). I had a lot of issues to get it to work as expected when I first started. What helped me was the example here:
https://binance-docs.github.io/apidocs/spot/en/#signed-trade-user_data-and-margin-endpoint-security
You can search for HMAC SHA256 signature
- they have an example with openssl and a fake key/secret. If your code can produce the same signature then it is working as expected – otherwise you have an issue somewhere in the code (i.e. maybe concurrency, object mutability or something in that manner)