Search code examples
jsonnode.jshmacwebhooksuber-api

How to validate the uber webhook api?


The Uber documentation say

The value of this field is a hexadecimal HMAC signature of the webhook HTTP request body, using the client secret as a key and SHA256 as the hash function.

But what is the HTTP request body? I assume it is the JSON body received from the webhook (https://developer.uber.com/docs/webhooks#section-example-post).

If it is, then how to validate it in NodeJS as the crypto module for HMAC doesn't accept JSON[I've tried to stringify the JSON, but it generates a different hash]. Or how to I convert the JSON into a buffer, since that is the next best option

If not, then what should I be using?

[UPDATE1] Code used for the task:

app.post("/",function(req,res){
const crypto = require('crypto');
var input = res.body
var str_input=JSON.stringify(input)

const hmac = crypto.createHmac('sha256', '<CLIENT SECRET>');

hmac.update(str_input);
console.log(hmac.digest('hex')); // print same as below
console.log("e034ac7db29c3c0c10dfeced41a6cd850ed74c1c3c620863d47654cc7390359a")
})

Solution

  • Updated Answer

    Uber considered the insertion of backslashes into webhook bodies a bug and released a fix. The workaround below will now break comparisons. As of 4/28/2016, clients written in Node should just perform the comparison without modifying the webhook body. Clients in languages that don't share Node's behavior of ignoring blackslashes in escape sequences are unaffected.

    Original Answer

    JS ignores the backslash when reading escape sequences in a string. The missing backslash is breaking your comparison because it's included in webhook event signatures.

    An immediate workaround is to re-insert those backslashes using a regex.

    var reconstitutedWebhookBody = input.replace(/\//g, '\\' + '/');

    That regex will need to be extended if webhooks ever start including other escapable characters.