In trying to verify Authorize.net webhook notifications in Node JS I've run into the following issue having to do with decimal numbers/trailing zeros:
Authorize.net forms a hash using HMAC-SHA512, with the body of the webhook notification and the merchant's Signature Key. That hash, and the hash I generate do not match.
Here is the JSON response from a test transaction in Postman which returns a decimal number for "authAmount" for an input of "300":
{
"_links": {
"self": {
"href": "/rest/v1/notifications/92782537-6a15-4e8f-8e2f-0710b1e6105d"
}
},
"notificationId": "92782537-6a15-4e8f-8e2f-0710b1e6105d",
"deliveryStatus": "Delivered",
"eventType": "net.authorize.payment.authcapture.created",
"eventDate": "2022-08-19T15:34:56.467",
"webhookId": "a8a17f6f-79eb-49f4-a047-436db0938bbb",
"payload": {
"responseCode": 1,
"authCode": "PYSH10",
"avsResponse": "Y",
"authAmount": 300.00, // <-- note the decimal number
"merchantReferenceId": "123456",
"entityName": "transaction",
"id": "60198731341"
},
"notificationDate": "2022-08-19T15:35:05.07"
}
Here is my code:
app.post('/notification', (req, res) => {
const authNetHash = req.header('X-ANET-Signature')
// req.body.payload.authAmount = req.body.payload.authAmount.toFixed(2)
const notificationBody = JSON.stringify(req.body);
const notificationHash = crypto.createHmac('sha512', config.AUTHORIZENET.signature_key)
.update(notificationBody)
.digest('hex');
console.log(req.body)
console.log(notificationBody)
console.log(`authorizenet_hash--> ${authNetHash}`)
console.log(`my_hash--> sha512=${notificationHash.toUpperCase()}`)
res.status(200).end()
})
and the resulting console log output:
{
notificationId: '92782537-6a15-4e8f-8e2f-0710b1e6105d',
eventType: 'net.authorize.payment.authcapture.created',
eventDate: '2022-08-19T15:34:56.4671136Z',
webhookId: 'a8a17f6f-79eb-49f4-a047-436db0938bbb',
payload: {
responseCode: 1,
authCode: 'PYSH10',
avsResponse: 'Y',
authAmount: 300,
merchantReferenceId: '123456',
entityName: 'transaction',
id: '60198731341'
}
}
{"notificationId":"92782537-6a15-4e8f-8e2f-0710b1e6105d","eventType":"net.authorize.payment.authcapture.created","eventDate":"2022-08-19T15:34:56.4671136Z","webhookId":"a8a17f6f-79eb-49f4-a047-436db0938bbb","payload":{"responseCode":1,"authCode":"PYSH10","avsResponse":"Y","authAmount":300,"merchantReferenceId":"123456","entityName":"transaction","id":"60198731341"}}
authorizenet_hash--> sha512=4ACA3F76717FBFB3E1FA38587A5057D62B2A6D70123D5B254804CBA461D1D9175CBC915B4DE6F13C43C78CF330DFFF3DC8579662C6CAFBEA7AC58D5D98E5A8DF
my_hash--> sha512=814C18B2A505E9B6385716E49D8C5AC143463741945F6E1FFE8C4450281C093C6D38308D06B1A41587D7E5EAEC1E8417BCC50D1D7039B47E3CEA2D0EE845455C
The hash mismatch is occurring as the parsed data is dropping the decimal value from "authAmount" as there is no fractional value. And of course this also occurs if a fractional value exists, but with a single decimal value (i.e. 300.10 would be parsed as 300.1). I realize this is how javascript treats decimals. Using toFixed(2)
on that value doesn't help as this returns a string, in which case the quotes throw the hash off.
I'm either missing the obvious or approaching this in a very stupid way, or both. I sure of it as I can't seem to find anyone having this problem.
Thanks in advance for any help.