Validate V3 signature fails if there is more than one Event in the webhook request

I can successfully validate webhook POST requests in PHP using the v3 signature (X-HubSpot-Signature-v3) as long as there’s no more than 1 event in the payload but the moment there is more than one event, the validation fails as the hash no longer matches.

Interestingly enough, this happens also using the official API client library (GitHub - HubSpot/hubspot-api-php: HubSpot API PHP Client Libraries for V3 version of the API · GitHub) when using Signature::isValid().

This is driving me up the wall, is there anyone who has had a similar issue and knows what the solution is? It is very easy to miss, because the payload does not often contain more than one event (unless they happen very close together).

Hey, @MTheodorsson :waving_hand: Welcome to our community. That definitely sounds like a frustrating experience, especially as it appears to be a bit sly in how it shows up.

I have a few troubleshooting questions:

  • Have you tried to validate the signature using static data that resembles the webhook payload with multiple events?
  • Have you tried logging to capture the raw payload and the steps of your signature validation process?

Thanks for the additional information! — Jaycee

Yes, I have used both a static payload and one that I captured from the webhook as it was being sent. You can see it below:

[{"eventId":2584008524,"subscriptionId":2429941,"portalId":143483564,"appId":2484474,"occurredAt":1704708338803,"subscriptionType":"contact.propertyChange","attemptNumber":0,"objectId":1051801,"propertyName":"lifecyclestage","propertyValue":null,"changeSource":"CRM_UI","sourceId":"userId:62129685"},
{"eventId":1997065984,"subscriptionId":2429941,"portalId":143483564,"appId":2484474,"occurredAt":1704708339803,"subscriptionType":"contact.propertyChange","attemptNumber":0,"objectId":1051801,"propertyName":"lifecyclestage","propertyValue":"417423609","changeSource":"CRM_UI","sourceId":"userId:62129685"}]

A payload that uses only one event, on the other hand, validates fine. Here is an example of a payload that works successfully:

[{"eventId":2968941740,"subscriptionId":2429941,"portalId":143483564,"appId":2484474,"occurredAt":1704193868623,"subscriptionType":"contact.propertyChange","attemptNumber":0,"objectId":1051801,"propertyName":"lifecyclestage","propertyValue":"422168280","changeSource":"CRM_UI","sourceId":"userId:62129685"}]

The issue might be with how it encodes the “,” in the first request or if the hashing of the initial signature uses some kind of buffer or formatting on the payload data, but without knowing how the hashing is done server-side, I have no means of figuring it out.

I suspect this might be an undiscovered bug on the Hubspot side.