Verifying a webhook

If you have created your webhook subscription using a signingKey you can validate the authenticity of the webhook by validating the request signature sent in the request header.

From the incoming webhook parse the following request headers:

messagebird-signature

messagebird-request-timestamp

In addition parse the request URL and the request Body.

To calculate the request signature:

  1. Base64 decode the messagebird-signature

  2. Create a SHA256 hash checksum of the request body and decode to a string

  3. Join the request timestamp ( messagebird-request-timestamp) with the request URL and checksum string computed in step 2

  4. Calculate HMACSHA256 using the signing key as the secret and the joined payload from step 3 to calculate the signature string encoded

  5. Compare the output of step 4 to the signature from step 1

Examples

import hashlib
import hmac
import base64
import time

class SignedRequest:
    def __init__(self, requestSignature, requestTimestamp, requestBody, requestUrl):
        self._requestSignature = requestSignature
        self._requestTimestamp = str(requestTimestamp)
        self._requestBody = requestBody
        self._requestUrl = requestUrl

    def verify(self, signing_key):
        payload = self._build_payload()
        expected_signature = base64.b64decode(self._requestSignature)
        calculated_signature = hmac.new(signing_key.encode('latin-1'), payload.encode('latin-1'),
                                        hashlib.sha256).digest()
        return expected_signature == calculated_signature

    def is_recent(self, offset=10):
        return int(time.time()) - int(self._requestTimestamp) < offset

    def _build_payload(self):
        checksum_body = hashlib.sha256(self._requestBody.encode('latin-1')).digest()
        str_checksum_body = checksum_body.decode('latin-1')
        parts = [self._requestTimestamp, self._requestUrl, str_checksum_body]
        return "\n".join(parts)

Last updated