How can we use evaluate block in postman flows to validate the hmac signed payload. I’m using the below code
const crypto = require('crypto');
const secret = 'mySecretKey';
const payload = request.body;
console.log(payload);
const receivedHmac = payload;
const data = JSON.stringify(payload);
const generatedHmac = crypto.createHmac('sha256', secret).update(data).digest('hex');
if (receivedHmac === generatedHmac) {
console.log('Payload is valid');
} else {
console.log('Payload is not valid');
}
This is throwing me an error invalid redefinition of global identifier.
“data” is a reserved variable, so I would change that to something else.
flows-daniel
(Daniel Kimmelmann)
January 28, 2025, 12:14am
3
Hi @avionics-specialist3
We support the web crypto API in the evaluate block.
Try the below code:
const secret = 'mySecretKey';
const payload = request.body;
console.log(payload);
const receivedHmac = 'expected_hmac_here';
const encoder = new TextEncoder();
const data = encoder.encode(payload)
crypto.subtle.importKey('raw', new TextEncoder().encode(secret), {
name: 'HMAC',
hash: 'SHA-256',
}, false, ['sign'])
.then((key) => crypto.subtle.sign('HMAC', key, data))
.then((signature) => {
const generatedHmac = Array.from(new Uint8Array(signature)).map(byte => byte.toString(16).padStart(2, '0')).join('');
return generatedHmac === receivedHmac;
})
.catch((error) => {return error});
If you want a constant time comparison function to compare the HMACs, you can use this function:
function constantTimeCompare(str1: string, str2: string): boolean {
if (str1.length !== str2.length) {
return false;
}
let result = 0;
for (let i = 0; i < str1.length; i++) {
result |= str1.charCodeAt(i) ^ str2.charCodeAt(i);
}
return result === 0;
}
constantTimeCompare(receivedHmac, generatedHmac)
The error you’re receiving in your code is in reference to trying to import the crypto library.
1 Like
Hi Daniel,
I am trying to verify signing keys in Postman. I was able to do this using CryptoJs:
const CryptoJS = require('crypto-js');
pm.test('JWT Signature is Valid', function () {
let recreatedSignature;
try {
// Generate the hash using HMAC-SHA256 and encode to Base64
recreatedSignature = CryptoJS.HmacSHA256(
`${jwtHeaderEncoded}.${jwtPayloadEncoded}`,
jwtSigningKey
)
.toString(CryptoJS.enc.Base64)
.replace(/=*$/, '');
console.log('recreatedSignature', recreatedSignature);
}
catch(e) {
throw new Error('Could not recreate signature | ' + e)
}
pm.expect(jwtSignature).to.be.a('string').that.equals(recreatedSignature);
});
However, require('crypto-js');
does not work for Newman tests, so I am trying to convert this to a Newman-friendly format.
I have not been able to implement this with your solution (modified for my purposes):
pm.test('JWT Signature is Valid', function () {
let recreatedSignature;
try {
const encoder = new TextEncoder();
const data = encoder.encode(`${jwtHeaderEncoded}.${jwtPayloadEncoded}`)
crypto.subtle.importKey('raw', new TextEncoder().encode(jwtSigningKey), {
name: 'HMAC',
hash: 'SHA-256',
}, false, ['sign'])
.then((key) => crypto.subtle.sign('HMAC', key, data))
.then((signature) => {
recreatedSignature = _arrayBufferToBase64(signature);
pm.expect(jwtSignature).to.be.a('string').that.equals(recreatedSignature);
})
.catch((error) => {console.log(error)});
}
catch(e) {
throw new Error('Could not recreate signature | ' + e)
}
});
// https://stackoverflow.com/a/9458996/27294094
function _arrayBufferToBase64( buffer ) {
var binary = '';
var bytes = new Uint8Array( buffer );
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return btoa( binary );
}
Furthermore, it looks like the Promise flow breaks the Chai tests - where it reports test success even when there is a failure.
Hi @matthew-beck-cpc
Can you make this question a new post tagged with Newman since it isn’t about flows? It’s not my area of expertise but i’m sure the experts there will be able to help you
1 Like