My question is very similar to Translation from Python to JavaScript: HMAC-SHA256, however that question was never answered.
The following Python code produces the correct hash:
def sign_api_request(api_secret, api_key, method, url):
encoded_url = urllib.parse.quote(url.lower(), '').lower()
timestamp = int(time.time())print("timestamp: " + str(timestamp))
nonce = str(uuid.uuid4())
signature = api_key + method + encoded_url + str(timestamp) + nonce
secret_bytes = base64.b64decode(api_secret)
signature_bytes = signature.encode('UTF8')
signature_hash = hmac.new(secret_bytes, signature_bytes, hashlib.sha256).digest()
base64_signature_hash = base64.b64encode(signature_hash).decode()
print(base64_signature_hash)
I'm trying to generate the same hash string using Javascript (as a Postman pre-request script). Here's what I've got:
function epochTime() {
var d = new Date();
var t = d.getTime();
var o = t + "";
return o.substring(0, 10);
}
function newGuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8; return v.toString(16); });
}
var uri_path = encodeURIComponent(request.url.toLowerCase()).toLowerCase();
var payload = uri_path; //.toLowerCase();
timestamp = epochTime();
nonce = newGuid();
signature = environment.api_key + "GET" + payload + timestamp + nonce;
secret_bytes = atob(environment.api_secret);
var hash = CryptoJS.HmacSHA256(signature, secret_bytes);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var sig = "amx " + environment.api_key + ":" + hashInBase64 + ":" + nonce + ":" + timestamp;
postman.setGlobalVariable("signature", sig);
If I use the same timestamp
and nonce
(by setting them explicitly rather than generating them at runtime) and the same api_key
and api_secret
(which are constant across calls) I expect to get the same value in sig
(Javascript) as I do in base64_signature_hash
(Python), however that's not the case.
I understand that this might be an encoding problem, but my js-fu is weak. Any ideas?
Edit to add: the method
and url
used for each are also the same.