APIs & Integrations

JurajMartinka
Member

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

I have problems with making it produce the same signature. I looked at various documentation including this https://legacydocs.hubspot.com/docs/faq/v2-request-validation

 

I also had a chat with Hubspot support and they linked this docs: https://developers.hubspot.com/docs/api/webhooks/validating-requests#validate-requests-using-the-v2-...

That's pretty much the same stuff as the first doc.

 

I use Clojure/Java to calculate the hash but I also tried the Python code Hubspot supplies and it produces the same hash as my application.

The trouble is that this SHA doesn't match the value of the 'x-hubspot-signature' header.

 

Here's the Python code:

 

 

 

import hashlib

client_secret = 'pat-na1-504...'
http_method = 'POST'
http_uri = 'https://....io/api/webhooks/hubspot'
request_body = '{"email":"test@email.com","company":"test","lastname":"test","firstname":"test"}'

source_string = client_secret + http_method + http_uri + request_body
print('source_string: {}'.format(source_string))

hash_result = hashlib.sha256(source_string.encode('utf-8')).hexdigest()
print('hash_result: {}'.format(hash_result))
    * 

 

 

 

 

I can provide the exact code including the full app secret and a couple of hubspot screenshots if needed separately.

(I can easily create another app since this isn't used in production yet).

 

UPDATE:

I also tried to compute the version 3 signature but to no avail. 

It again produces a different hash than what's in the request header x-hubspot-signature-v3.

The documentation isn't explicit about what variant of Base64 encoding should be used (url-safe or not; with or without padding - it's with padding based on the actual value I got in the request header)  but I tried all of them and neither worked.

 

I also noticed that the new docs for version 2 signature don't say how the result should be encoded, but I assume it's as before, that is Hex encoding.

 

0 Upvotes
1 Accepted solution
tominal
Solution
Guide | Partner
Guide | Partner

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

I had a feeling after reading your original post the first time that something was off about that secret key. That's a private app key! "pat-na1" stands for Private App Token in North America. That would explain why even after all of that, it still is incorrect.

 

The secret keys the documentation is referring to are developer apps where you are given a client ID and client secret key. Developer app secrets are in the UUID format. Here's a link to how to create a developer app:

 

https://developers.hubspot.com/docs/api/creating-an-app


Thomas Johnson
Community Champion


Kahu Software LLC
A Texan HubSpot consulting firm
https://kahusoftware.com

View solution in original post

0 Upvotes
5 Replies 5
Jaycee_Lewis
Community Manager
Community Manager

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

Hi, @JurajMartinka 👋 Thanks for reaching out. Let's see if we can get the conversation going for you — hey @nikodev @JBeatty @tominal, do you have any experience here? Thank you for taking a look! — Jaycee

linkedin

Jaycee Lewis

Developer Community Manager

Community | HubSpot

tominal
Guide | Partner
Guide | Partner

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

Hey @JurajMartinka,

 

I can tell you I spent days trying to get PHP to match HubSpot's signature. I'll paste my v3 code here to break it down. Hopefully other PHP developers will roll across this post and save them time. It's not fun.

 

$timestamp = $request->headers->get('X-HubSpot-Request-Timestamp');
$hash = hash_hmac('sha256', 'GEThttps://yourdomain.com' . $request->getRequestUri() . (strlen($request->getContent()) > 0 ? $request->getContent() : '') . $timestamp, {your_client_secret}, true);

// Reject the timestamp if older than a few minutes

if(!hash_equals($request->headers->get('X-HubSpot-Signature-v3'), base64_encode($hash)) // Error out if the hashes don't match

 

Breakdown:

  • HTTPS your domain
  • Make sure that the body is just the body of the request
  • Concat the timestamp from the headers
  • Pass your client secret as the key of your hash function
  • The hash function has to spit out the raw binary output of the hash otherwise it will output lowercase hexits
  • Base 64 encode that puke

This will be equivalent to the X-HubSpot-Signature-v3 header.

 

If I had more time I would convert that to a Python version.

 

Hope that helps!


Thomas Johnson
Community Champion


Kahu Software LLC
A Texan HubSpot consulting firm
https://kahusoftware.com
0 Upvotes
JurajMartinka
Member

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

Thanks for the details, very much appreciated.

 

Unfortunately, I already did all of that a couple of days ago and it simply doesn't work.

 

The string I'm trying to sign looks like this which I checked a few time and it looks good to me:

 

#!/usr/local/bin/php

<?php
$document = 'POSThttps://example.com/api/webhooks/hubspot/trial-requested{"email":"test@email.com","company":"Test value","lastname":"Test value","firstname":"Test value"}1669136688223';
$secret = 'pat-na1-504...';
$hash = hash_hmac('sha256', $document, $secret, true);

print "signature:" . base64_encode($hash);
?>

 

The actual hostname is different but I tried your PHP code and it produces the same signature as my code, that is this value in my case (with proper hostname): 

R9Eb1i4n/vzEollD9qFu6h+LDMSbMAN0ckn8RJHiAJc=

 

Yet the value in the x-hubspot-signature-v3 header is completely different, that is EmURxhKIXoSDml+j/GSmf5jUrfLckNQatujkHhwHMpw=.

 

As a last resort, I tried to hardcode the request method to "GET" (although that's obviously incorrect in my case) but it doesn't match either.

 

 

Now I'm stuck - there might be some little detail, but I don't really know what's going on :(.

 

 

 

tominal
Solution
Guide | Partner
Guide | Partner

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

I had a feeling after reading your original post the first time that something was off about that secret key. That's a private app key! "pat-na1" stands for Private App Token in North America. That would explain why even after all of that, it still is incorrect.

 

The secret keys the documentation is referring to are developer apps where you are given a client ID and client secret key. Developer app secrets are in the UUID format. Here's a link to how to create a developer app:

 

https://developers.hubspot.com/docs/api/creating-an-app


Thomas Johnson
Community Champion


Kahu Software LLC
A Texan HubSpot consulting firm
https://kahusoftware.com
0 Upvotes
JurajMartinka
Member

Workflow webhook signature validation - sha256 produced by my code doesn't match the request header

SOLVE

Fantastic, thanks a ton!

This was indeed the problem.

 

Do you know why Private Apps don't work with webhooks?

They looked like a great fit for my task: 

JurajMartinka_0-1669178541887.png

 

0 Upvotes