Validating requests from HubSpot

 

To ensure that the requests that your integration is receiving from HubSpot are actually coming from HubSpot, we populate two headers: X-HubSpot-Signature and X-HubSpot-Signature-Version.

The X-HubSpot-Signature header will contain the signature that will need to be verified. The method used to verify the signature will depend on the version of the signature.

The X-HubSpot-Signature-Version header will contain a version number, i.e. v2, that will indicate which method should be used to verify the signature included in X-HubSpot-Signature.

See the documentation pages below for details on verifying the different versions of the signature.


Validating the v1 request signature:

When the request from HubSpot is sent with the X-HubSpot-Signature-Version header set to v1, the X-HubSpot-Signature header will be an SHA-256 hash built using the client secret of your app combined with details of the request.

To verify this signature, perform the following steps:

  • Create a string that concatenates together the following: Client secret request body (if present)
  • Create a SHA-256 hash of the resulting string.
  • Compare the hash value to the signature.
    • If they're equal then this request has passed validation.
    • If these values do not match, then this request may have been tampered with in-transit or someone may be spoofing requests to your endpoint.

Example for a request with a body:

JSON
//Client secret : yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
// Request body: [
{"eventId":1,"subscriptionId":12345,"
portalId":62515",
occurredAt":1564113600000",
subscriptionType":"contact.creation",
"attemptNumber":0,
"objectId":123,
"changeSource":"CRM",
"changeFlag":"NEW",
"appId":54321}
]

v1 request signature examples: 

NOTE: This is only an example for generating the expected hash.
You will need to compare this expected hash with the actual hash in the 
X-HubSpot-Signature header.

>>> import hashlib

>>> client_secret = 'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy'
>>> request_body = '[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
>>> source_string = client_secret + request_body
>>> source_string
'yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy[{"eventId":1,"subscriptionId":12345,"portalId":62515,"occurredAt":1564113600000,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":54321}]'
>>> hashlib.sha256(source_string).hexdigest()
'232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de'
      

The resulting hash would be:
232db2615f3d666fe21a8ec971ac7b5402d33b9a925784df3ca654d05f4817de


Validating the v2 request signature:

When the request from HubSpot is sent with the X-HubSpot-Signature-Version header set to v2, the X-HubSpot-Signature header will be an SHA-256 hash built using the client secret of your app combined with details of the request.

To verify this signature, perform the following steps:

  • Create a string that concatenates together the following: Client secret + http method + URI + request body (if present)
  • Create a SHA-256 hash of the resulting string.
  • Compare the hash value to the signature.
    • If they're equal then this request has passed validation.
    • If these values do not match, then this request may have been tampered with in-transit or someone may be spoofing requests to your endpoint.

    Notes:
    • The URI used to build the source string must exactly match the original request, including the protocol. If you're having trouble validating the signature, ensure that any query parameters are in the exact same order they were listed in the original request.
    • The source string should be UTF-8 encoded before calculating the SHA-256 hash.

Example for a GET request:



Example for a request with a body:

v2 request signature examples: