In order to integrate with any webhook implementation, be that Claims Manager or any other webhook provider, you first need to expose a publically facing endpoint on the internet in order to receive the webhooks. Ensuring that these communications are secure is vital. Let's look at the steps you can take to protect your endpoint
As with any activity on the internet, it is strongly recommended to secure this traffic by ensuring that your endpoint is using HTTPS to encrypt the data as it is sent over the wire. In our live envrionment, we will not accept a webhook endpoint that doesn't use HTTPS. To support partners who may not have SSL certificates installed in lower environments, our test environment will accept a plain HTTP endpoint, but be aware that the live environment must use an SSL certificate from a trusted certificate provider, self-signed certificates will not be accepted.
When setting up your webhook endpoint in Claims Manager, you can add a header to the payload that we will send you. This can include a unique API Key that only you know so
you can be more confident that the request came from us. This header name and value can be anything you like (within the standard limitations of HTTP Headers). The standard
prefix for user defined headers is to prefix them with X-
so you may want to call your header X-MyCompany-APIKey
for example. Then when processing
the request, you can look for this header and check the value matches what your are expecting.
Claims Manager signs all webhooks sent out to protect the data from being tampered with, or resent at a later date in a replay attack. To protect your application, it is recommended that you validate this signature before responding to any request. Given that the signature also includes a timestamp, an attacker is unable to change the timestamp without invalidating the signature. Your application can then use this timestamp to check that the webhook being sent is not too old; we suggest a tolerance of 5 minutes is enough to mitigate any delay on our side sending the request.
If you are validating the timestamp in the signature, be sure that your server's clock is accurate by using the Network Time Protocol to ensure that you are in sync with Claims Manager servers.
Each webhook sent from Claims Manager will include a X-Crawford-Signature
header in the HTTP message headers. In order to validate that the signature is correct, you will also need
the clientId
that you use to authenticate to the Claims Manager API. The signature is made up of the unix timestamp (the number of seconds since the 1st of January 1970 at UTC), a
colon and then the computed HMAC using the SHA256 hash function using your clientId
as the key.
The steps you need to take to regenerate the signature are as follows:
X-Crawford-Signature
header in the request message and split the value on the colon to leave you with the first string, which is the timestamp
and the second string which is the signature..
and the raw JSON payload of the webhook into one string to compute the HMAC with.clientId
as the key. Compare this generated signature with the one extracted from the header and ensure that they match.Note that you require the raw json body of the request to correctly perform the signature validation. Any manipulation of the formatting or line endings, for example, may cause vlaidation to fail.
Let's walk through an example. Let's assume your clientId
is abcde123456 and you received the following webhook:
HTTP POST 1.1
X-Crawford-Signature: "1492774577:2739262ab5f97fed7537e6b6ed2a48eb3e50d49f6c708ae5fc536f1d9719f61f"
{
"event":"Incident Status",
"action":"Updated",
"incidentId":6904165,
"resource":"/incidents/6904165",
"createdDateTime":"2023-12-28T21:24:52.410",
"data":{
"newStatus":"Closed",
"previousStatus":"Open"
}
}
First we split the X-Crawford-Signature
header into the timestamp (1492774577) and the signature to validate (2739262ab5f97fed7537e6b6ed2a48eb3e50d49f6c708ae5fc536f1d9719f61f).
Next we concatenate the timestamp, the character .
and the raw JSON request body to get the following string:
1492774577.{
"event":"Incident Status",
"action":"Updated",
"incidentId":6904165,
"resource":"/incidents/6904165",
"createdDateTime":"2023-12-28T21:24:52.410",
"data":{
"newStatus":"Closed",
"previousStatus":"Open"
}
}
We then use this string to compute the HMAC using the SHA256 hash function and our clientId
(abcde123456) as the key. This gives us a value of 2739262ab5f97fed7537e6b6ed2a48eb3e50d49f6c708ae5fc536f1d9719f61f
which we can verify is the same value as the second half of the X-Crawford-Signature
header value. Below is an example implementation using node.js.
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
const clientId = '**Replace with your clientId**';
function verifySignature(signature, payload) {
const hmac = crypto.createHmac('sha256', clientId);
const signatureParts = signature.split(":");
const timestamp = signatureParts[0];
const signatureHash = signatureParts[1];
const preparedPayload = timestamp.concat(".", Buffer.from(payload, 'utf-8'));
const data = hmac.update(preparedPayload);
const gen_hmac = data.digest('hex');
return signatureHash === gen_hmac;
}
app.post('/api/webhook', bodyParser.raw({inflate:true, limit: '100kb', type: 'application/json'}), (request, response) => {
const event = request.body;
if (verifySignature(request.get("X-Crawford-Signature"), request.body))
response.json({received: true});
else
response.send(401, "unauthorised");
});
app.listen(8000, () => console.log('Running on port 8000'));