Hi all,
I am trying to complete the setup of a webhook to send data into create.
The webhook authentication is fairly standard. Provider will hash the raw payload using a pre-shared key, add that to the headers, we hash the body our end and compare.
Unfortunately I am running into issues matching up the hashes, and my suspicion is that liberty create is doing something to the body on arrival to the endpoint despite the data processor saying that it is the raw data.
My data processor:
return {
main: function(fields, context) {
const request = fields;
const secret = cs.variable(cs.ref("variable_circuit_secret"));
const messageHash = cs.hash(fields["payload"], 'sha256', secret);
request["passthrough"] = messageHash;
return request
}
}
I pass through the hash generated our end so that I can compare it to the one generated on the providers side in the auth code, however, no luck so far.
If anyone has any insights into this functionality, has done it before, or can confirm that create sends the raw data into the data processor, help would be appreciated.
Thanks,
Dan.
Hi, yes fields["payload"]
is the raw payload data received.
Hard to know what might be wrong, but there is always risk with this approach, the slightest discrepancy in what is hashed (an extra line return or space on the end for example) will invalidate it.
You may not have control over this, but it might be better to hash a concatenated string of some or all of the field values, so that the JSON wrapping itself doesn’t add any ambiguity.
1 Like
Hi Bob,
I will spin up an endpoint in the cloud and point it to that and verify.
Like you said, it is always tough as one discrepancy in the raw body is a completely different hash.
Thanks for responding, I will update here with what I find
Dan.
It turns out that the provider was supplying the incorrect secret to us, so after a call to go through the integration settings on their software all was well.
I will document the approach for this type of auth in create if anyone is searching the forum in future:
Set up a generic endpoint and generic function.On the request payload processor, generate your hash following the documenation from the webhook provider.Add this hash to the passthrough so your auth code can access it.
return {
main: function(fields, context) {
const request = fields;
const secret = "REFERENCE_TO_SECRET";
const messageHash = cs.hash(fields["payload"], 'sha256', secret);
request["passthrough"] = messageHash;
return request
}
}
On the endpoints auth processor compare the passed through hash to the one supplied in the header.
function constantTimeCompare(a, b) {
if (a.length !== b.length) return false;
let result = 0;
for (let i = 0; i < a.length; i++) {
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return result === 0;
}
return {
main: function (input, params) {
const headersCircuitHash = params["request_headers"]["circuit-signature"];
const libertyCreateHash = params["passthrough"];
if (!constantTimeCompare(headersCircuitHash, libertyCreateHash)) cs.error("Hash mismatch")
return true;
}
}
You should then be able to map incoming data from the webhook securely.
3 Likes