Secure your webhooks

Once you created webhooks from the dashboard and want to integrate them, please keep in mind you need to secure them, in order to avoid any vulnerability in your system.

1. Whitelist our IP address

The first thing to do to add security is to whitelist our IP addresses to make sure nobody else than us call your urls. We will always call your callback URL from the same IP addresses:

63.32.31.5
52.215.247.62
34.249.92.209

2. Use the provided secret to check the signatures

Webhooks Signature

When a webhook is created, a secret is automatically generated. This secret will be used to sign every event that will be sent to your endpoint. The secret is only shown once after the creation of the webhook or after updating the current secret. You have the ability to update your secret from the dashboard by editing an existing webhook. The older secret will then expire 24 hours after this update, giving you time to replace it in your backend.

🚧

A webhook cannot have more than 2 secrets at the same time

At a given time, a webhook cannot have more than two signatures, meaning that if you update your secret twice in a row without updating your code, the first secret won't be valid anymore

Check the webhook signatures

Verify the events that we send to your webhook endpoints. We sign the events by including a signature in each event’s BridgeApi-Signature header. This allows you to verify that the events were sent by Bridge, not by a third party.

The BridgeApi-Signature header included in each signed event contains one or more signatures. Each signature is prefixed by a scheme. Schemes start with v, followed by an integer. Currently, the only valid live signature scheme is v1.

Example:

BridgeApi-Signature:
v1=E5637CDB3A54ECA10DDA9D515E588B6BECDABA414537FFC488B63474081B90DF,v1=82918263E23D1A67DD5B47E190AB62EAF9DDBB9920F48569120ED67E95286CF4

We generate signatures using a hash-based message authentication code (HMAC) with SHA-256. To prevent downgrade attacks, you should ignore all schemes that are not v1.

📘

It is possible to have multiple signatures with the same scheme-secret pair

This can happen when you update a webhook's secret from the Dashboard, because the previous secret is still active for up to 24 hours. During this time, your callback URL has multiple active secrets and we generated one signature for each secret.

Step 1: Extract the signatures from the header
Split the header, using the , character as the separator, to get a list of elements. Then split each element, using the = character as the separator, to get a prefix and value pair. The value for the prefix v1 corresponds to the signature (or signatures). You can discard all other elements.

Step 2: Determine the expected signature
Compute an HMAC with the SHA256 hash function. Use the endpoint’s signing secret as the key, and use the received event, in the string format, as the message.

Step 3: Compare the signatures
Compare the signature (or signatures) in the header to the expected signature.

3. Signature verification: examples

In the following examples, SECRET is the secret of your signature and PAYLOAD is the whole body sent by the webhook. If you try these examples with the following values:

SECRET = “644b2ac3-0797-4ec6-9537-cb5c0af9caf9”

PAYLOAD = "{\"content\":{\"item_id\":1234567890,\"status\":0,\"user_uuid\":\"9a95b38f-f98b-417a-988b-9d0d584893e7\"},\"timestamp\":1611681789,\"type\":\"TEST_EVENT\"}"

You should obtain: FAA8ECAC21DA6405D789C76EDB4003756398E7169DACC3FA70CF5919A81374A8

See these codes examples to get this result:

var crypto = require('crypto');
var hash = crypto.createHmac('SHA256', SECRET).update(PAYLOAD).digest('hex');
console.log(hash.toUpperCase());
Mac hasher = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(SECRET.getBytes(), "HmacSHA256");
hasher.init(secretKey);
byte[] signedContent = hasher.doFinal(PAYLOAD.getBytes());
System.out.println(DatatypeConverter.printHexBinary(signedContent));
import hmac
import hashlib

signature = hmac.new(bytes(API_SECRET , 'utf-8'), msg = bytes(message, 'utf-8'), digestmod = hashlib.sha256).hexdigest().upper()
print(signature)

What’s Next