Validating a webhook response
Kintaba sends a signature with every Webhook request that you can optionally use to validate requests came from Kintaba.
We send webhook signatures under the X-KINTABA-SIGNATURE
header, and they look like this:
t=1629902182,
v1=ac707831618bc7d68af35577b5b775dd9004f0da493165ec3b06699653e4d571
The example above shows the signature on two lines, but note that the actual signature comes on one line with no whitespace.
Verifying signatures
Kintaba generates signatures using HMAC with SHA256. You'll need some utility for generating proper HMACs.
Step 1: Extract the signature and timestamp
Extract the timestamp and the signature from the response header by splitting on the ,
, then for each respective field, split on =
to extract the value from each key-value pair.
The value for t
is the timestamp, and the value for v1
is the signature.
Step 2: Create the payload to sign and verify
Create the signed_payload
string by concatenating:
- The timestamp (the value under
t
as extracted in Step 1) - The literal character
.
- The request body (i.e. the JSON payload)
Step 3: Extract the secret key from Kintaba
You'll need the webhook URL's secret key to validate the signature. To do so, navigate to the automation with the webhook in question, and click the icon to open the webhook's configuration modal:


Inside the modal, you can click the eye button to view the secret, copy this secret:


Step 4: Use the secret key and signing payload to generate a signature
Using the signing key extracted in step 3 and the payload generated in step 2, generate an HMAC with SHA-256 with the signing key as the secret and the payload as the message.
Step 5: Validate the signature and timestamp
Compare the value under the v1
field in step 2 with the signature just generated. They should match.
Additionally, to prevent replay attacks, where an attacker captures a valid webhook request and replays it against your webhook URL over and over again, you should check the timestamp extracted in step 2 and ensure it isn't too far in the past (5 minutes is a good target).
If everything matches, congratulations, you've validated your webhook!
Example verification code
Python
#!/usr/bin/env python3
# Verifies signatures for Kintaba webhooks.
# note: the signature lives in the 'x-kintaba-signature' header.
import hmac
from hashlib import sha256
def _get_timestamp_and_sig(header):
items = [i.split("=", 2) for i in header.split(",")]
timestamp = int([i[1] for i in items if i[0] == "t"][0])
signature = [i[1] for i in items if i[0] == "v1"][0]
return timestamp, signature
def _create_sig(payload, secret):
mac = hmac.new(
secret.encode("utf-8"),
msg=payload.encode("utf-8"),
digestmod=sha256,
)
return mac.hexdigest()
def verify_payload(payload, header, secret, tolerance_in_secs=None):
timestamp, signature = _get_timestamp_and_sig(header)
if not signature:
return false
signed_payload = "%d.%s" % (timestamp, payload)
computed_sig = _create_sig(signed_payload, secret)
if computed_sig != signature:
return False
if tolerance_in_secs and timestamp < time.time() - tolerance_in_secs:
return False
return True
Updated 10 months ago