APIs & Integrations

philipnilsson
Member

Unable to correctly validate v2 request signature

SOLVE

I'm trying to follow the steps at https://developers.hubspot.com/docs/faq/v2-request-validation.

 

In order to validate the hubspot signature, but am currently unable to produce a hash consistent with what I'm seeing in the  X-HubSpot-Signature value. I suspect this is because the URL I'm putting into the library is not exactly the correct one, but can't be sure. I.e. I suspect the problem may be similar to having a unexpected trailing slash, badly encoded query parameter or something like that.

 

I'm using node.js / express, and I'm producing the hash exactly using the method from the code example from the support page. Inputting the example source strings provided does indeed produce the expected checksums.

 

Is there any way to debug this issue? E.g. being able to see the input source string that HubSpot actually uses to produce the value in X-HubSpot-Signature?

 

I'm currently only trying to make a GET-request work, so producing the input source string should be straight-forwards. For the sake of it, here's the express code that creates the string.

 

import crypto from 'crypto';

function validateHubspotSignature(req, res) {
  const HubspotSignature = req.get('X-HubSpot-Signature');
  
  const stringToHash =
    process.env.HUBSPOT_CLIENT_SECRET
    + req.method
    + req.protocol + '://' + req.get('host') + req.url;

  const hash =
    crypto.createHash('sha256').update(stringToHash).digest('hex');

  // Expecting `hash` and `HubspotSignature` to match, but they do not.
};

 

I've tried using req.originalUrl etc as well. (I've of course also verified that protocal and method etc are what I expect, and even tried with different combinations, all to no luck).

 

Thanks,

Philip

0 Upvotes
1 Accepted solution
Frederick
Solution
Participant

Unable to correctly validate v2 request signature

SOLVE

Incase this is helpful for anyone, I've been trying to inpliment the V2 signature validation using AWS Lambda, unfortunately AWS API Gateway does not expose the original URL and I've been trying to reconstruct it using the queryStringParameters attribute of the event object. Using Postman, I was able to set up a mock server which I pointed the HubSpot API towards. Postman then provided me with an example URL that HubSpot made it's GET request to, I could then use this URL as a template for reconstruction.

 

One thing to note, AWS decodes the URL parameters so for a URL like https://www.google.com/search?q=HubSpot%20API, AWS Lambda will provide the parameters like so:

 

print(event["queryStringParameters"])

{"q":"HubSpot API"}

 

 

So to reconstruct the URL, you need to encode each of the URL parameters using the urllib.parse.quote_plus function:

 

from urllib.parse import quote_plus

params = [["userId","123"],["userEmail","me@company.com"],["associatedObjectId","123456"],["associatedObjectType","DEAL"],["portalId","12345"]]

url_query = []

for p in params:
    url_query.append(p[0] + "=" + quote_plus(p[1]))

url_query = "&".join(url_query)

print(url_query)

userId=123&userEmail=me%40company.com&associatedObjectId=123456&associatedObjectType=DEAL&portalId=12345

 

 

 

 

Then you can join it back to the original URL:

 

url = "https://www.example.com/api"
url_query = "userId=xxx&userEmail=xxx%40xxx.com&associatedObjectId=xxx&associatedObjectType=xxx&portalId=xxx"

completeURL = url + "?" + url_query

 

 

Note that the email address will always contain an @ symbol, so the URL encoding step is always needed to convert @ to %40.

View solution in original post

7 Replies 7
EM9
Participant

Unable to correctly validate v2 request signature

SOLVE

Also ran across the the same issue. I wonder if there's any way to solve without hardcoding the specifc order or params as api gateway re-organises them 😞

0 Upvotes
Frederick
Solution
Participant

Unable to correctly validate v2 request signature

SOLVE

Incase this is helpful for anyone, I've been trying to inpliment the V2 signature validation using AWS Lambda, unfortunately AWS API Gateway does not expose the original URL and I've been trying to reconstruct it using the queryStringParameters attribute of the event object. Using Postman, I was able to set up a mock server which I pointed the HubSpot API towards. Postman then provided me with an example URL that HubSpot made it's GET request to, I could then use this URL as a template for reconstruction.

 

One thing to note, AWS decodes the URL parameters so for a URL like https://www.google.com/search?q=HubSpot%20API, AWS Lambda will provide the parameters like so:

 

print(event["queryStringParameters"])

{"q":"HubSpot API"}

 

 

So to reconstruct the URL, you need to encode each of the URL parameters using the urllib.parse.quote_plus function:

 

from urllib.parse import quote_plus

params = [["userId","123"],["userEmail","me@company.com"],["associatedObjectId","123456"],["associatedObjectType","DEAL"],["portalId","12345"]]

url_query = []

for p in params:
    url_query.append(p[0] + "=" + quote_plus(p[1]))

url_query = "&".join(url_query)

print(url_query)

userId=123&userEmail=me%40company.com&associatedObjectId=123456&associatedObjectType=DEAL&portalId=12345

 

 

 

 

Then you can join it back to the original URL:

 

url = "https://www.example.com/api"
url_query = "userId=xxx&userEmail=xxx%40xxx.com&associatedObjectId=xxx&associatedObjectType=xxx&portalId=xxx"

completeURL = url + "?" + url_query

 

 

Note that the email address will always contain an @ symbol, so the URL encoding step is always needed to convert @ to %40.

AChong1
Contributor

Unable to correctly validate v2 request signature

SOLVE

  

You can inspect the request URL being sent to your API from https://requestbin.com, where you'll see all these paramters. 

 

@philipnilsson

0 Upvotes
RMcKenzie
Member

Unable to correctly validate v2 request signature

SOLVE

I realize this is very late, however I recently encountered this issue and in hopes of saving someone else the time I thought I'd share. 

 

I was trying to validate the CRM Contact Card request which is a GET request. I was stuck for quite a while because I was passing in the exact path it was calling, as per the documentation.

What I expected: "https://mypathhere/api/v1/myfunctionname"

What it turned out to be: "https://mypathhere/api/v1/myfunctionname?userId=???????&userEmail=????????&associatedObjectId=????&associatedObjectType=CONTACT&portalId=??????"

Trouble is, the CRM Contact Card appears to add extra parameters to the query that I wasn't aware of.

I thought they had to be set explicitly but they seem to be sent by default. 

 

 

 

 

 

AChong1
Contributor

Unable to correctly validate v2 request signature

SOLVE

yes, you can see these params in your postman mock server in the order hubspot likes them. In serverless functions, you'll need to add portal ID manually to the params since it's apparently not received by the serverless function. 

0 Upvotes
WendyGoh
HubSpot Employee
HubSpot Employee

Unable to correctly validate v2 request signature

SOLVE

Hi @philipnilsson,

 

I hope all is well with you 😄

 

Do you mind sharing with me the request here that you're verifying the signatures for? E.g. Webhook Workflow. This is because the concatention of the X-HubSpot-Signature header is different from the Webhooks API. As documentated here: Verify request signatures in workflow webhooks.

 

Additionally, could you also share with me the value for stringToHash before the value has been hashed so that I can take a further look into it?

 

If you're more comfortable, you can share these information across via DM.

AChong1
Contributor

Unable to correctly validate v2 request signature

SOLVE

HI Wendy,

 

What does the concatenation typically look like in this case? 

0 Upvotes