Reputation: 1515
I'm developing a Node.js app and I'm struggling validating the Mandrill Webhook request.
As stated here http://help.mandrill.com/entries/23704122-Authenticating-webhook-requests it should be something like this in PHP:
/**
* Generates a base64-encoded signature for a Mandrill webhook request.
* @param string $webhook_key the webhook's authentication key
* @param string $url the webhook url
* @param array $params the request's POST parameters
*/
function generateSignature($webhook_key, $url, $params) {
$signed_data = $url;
ksort($params);
foreach ($params as $key => $value) {
$signed_data .= $key;
$signed_data .= $value;
}
return base64_encode(hash_hmac('sha1', $signed_data, $webhook_key, true));
}
So I came up with this:
var url = "http://....";
var post = "<POST Data>";
require('crypto').createHmac("SHA1", "<Webhook Signature Key>").update(url+post).digest("base64");
Unfortunately, this doesn't work. I get a different signature.
The POST data comes urlencoded, e.g.:
mandrill_events=%5B%7B%22event%22%3A%22inbound ...
Urldecoded:
mandrill_events=[{"event":"inbound ...
The Mandrill doc says, that the delimiter should not be included, so this is the string I'm using (without =
):
mandrill_events[{"event":"inbound ...
Any ideas about that?
PS: I double checked the URL and the Webhook Key :-).
Upvotes: 5
Views: 3062
Reputation: 16666
Use the URL (config.url
in the example) and the key (config.key
) that is displayed in https://mandrillapp.com/settings/webhooks for that specific Webhook.
In addition to the above response you have to make sure that forward slashes are escaped with a single backslash.
// mandrillEventsParamVal - how you get that depends on your request processor chain
var paramValEscaped = mandrillEventsParamVal.replace(/\//g, '\\\/');
var input = config.url + 'mandrill_events' + paramValEscaped;
var check = crypto.createHmac('sha1', config.key).update(input, 'utf8', 'binary').digest('base64');
The String called check
is what you check against the header 'X-Mandrill-Signature'.
Upvotes: 3
Reputation: 2217
The problem comes from your input data format. You have to concat key/value pair, example:
var data = URL; for(var key in POST_DATA) data += key+POST_DATA[key];
And now, you can check if base64(sha1(data, mkey)) is equal to the signature.
Upvotes: 1