cancel
Showing results for 
Search instead for 
Did you mean: 

How to verify a webhook request sign

pichiste
Honored Guest

I have successfully set up and verified a webhook endpoint as described in the docs, but upon receiving Event Notification requests, I am stuck at the step of validating the payload. The documentation says the process is as follows (source):

We sign all Event Notification payloads with a SHA256 signature and include the signature in the request's X-Hub-Signature-256 header, preceded with sha256=. You don't have to validate the payload, but you should.

To validate the payload:

  1. Generate a SHA256 signature using the payload and your app's App Secret.
  2. Compare your signature to the signature in the X-Hub-Signature-256 header (everything after sha256=). If the signatures match, the payload is genuine.

 

However, in my implementation I cannot get the comparison/verification to work. This is the code (node.js) that I'm using to verify the signatures:

function verifyPayload(secret, payload, signature) {
    const hmac = crypto.createHmac("sha256", secret);
    const expectedSignature = "sha256=" + hmac.update(payload).digest("hex");
    return crypto.timingSafeEqual(
        Buffer.from(expectedSignature),
        Buffer.from(signature)
    );
}
 
Here is a Python version for completeness:
 
def verify_payload(secret, payload, signature😞
    expected_signature = "sha256=" + hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected_signature, signature)
  
Where:
secret = the Quest app secret
payload = request body JSON string received
signature = the signature in the "X-Hub-Signature-256" header
 
Is there a different approach that should be used to accomplish this?
 
I should also note that the information on the application webhook management page seems out of date:
 
We sign all Event Notification payloads with a SHA1 signature and include the signature in the request's X-Hub-Signature header...
 
 
1 REPLY 1

pichiste
Honored Guest

As it turns out those functions do actually work... the problem was that the escape characters in the "developer_payload" field value of "\"\"" were being removed by my VS Code formatter when I hardcoded the value for testing, so the resulting hash was different.