Validating HubSpot Webhook Request Signatures v3 Using Secret Keys in Node.js
Verify hubspot webhook signature v3 nodejs applications accurately in production environments to prevent unauthorized payload injection, validate request origins, and protect CRM integrations. Validating HubSpot’s v3 webhook signature (X-HubSpot-Signature-v3) in Node.js fails when developers concatenate the wrong request signature string or accidentally pass a Private App Access Token instead of the Client Secret. Unlike simpler HMAC schemes that hash only the request body, HubSpot v3 constructs an HMAC-SHA256 signature from a concatenated UTF-8 string consisting of four exact parts: requestMethod + requestUri + requestBody + timestamp. If your Express code uses req.url instead of the full public requestUri (e.g., missing the https:// protocol, host, or query parameters), the string fed to the crypto digest diverges from what HubSpot computed on dispatch, throwing validation errors and unwanted 401 statuses.
To ensure your system parses incoming event streams accurately, you can use our HookDoc Tool to inspect raw payloads, review headers, and debug JSON objects in real time.
Step-by-Step Guide: How to Verify HubSpot Webhook Signature V3 Nodejs Handlers
Another major hurdle is timestamp validation and base64 encoding. HubSpot includes an X-HubSpot-Request-Timestamp header in millisecond Unix epoch format. You must reject any request where the delta between the current time and this timestamp exceeds 300,000 milliseconds (5 minutes) to guard against replay attacks. When hashing, standard hex output (.digest('hex')) will also cause validation failure—HubSpot requires the HMAC digest to be Base64-encoded (.digest('base64')).
To resolve this issue when you configure logic to verify hubspot webhook signature v3 nodejs endpoints, preserve the unparsed body Buffer via Express middleware, reconstruct the absolute, fully qualified URL targeted by HubSpot, and verify that your secret key comes from your Developer App’s Auth tab or Private App settings (not the API access token pat-na1...). Compare the computed base64 signature with X-HubSpot-Signature-v3 using constant-time string buffers. For full specification details, review the Official HubSpot Webhook Security Documentation.
The Code Fix
JavaScript
const crypto = require('crypto');
/**
* Helper function to verify hubspot webhook signature v3 nodejs endpoints safely.
*/
function verifyHubSpotV3(req, clientSecret) {
const signature = req.headers['x-hubspot-signature-v3'];
const timestamp = req.headers['x-hubspot-request-timestamp'];
// Reject missing headers or requests older than 5 minutes (300,000 ms)
if (!signature || !timestamp || Math.abs(Date.now() - Number(timestamp)) > 300000) return false;
// Construct the fully qualified request URI (protocol + host + originalUrl)
const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
const rawBody = req.rawBody ? req.rawBody.toString('utf-8') : '';
// Concatenate: requestMethod + requestUri + requestBody + timestamp
const sourceString = req.method + fullUrl + rawBody + timestamp;
// Generate HMAC SHA-256 digest encoded in Base64 (not hex)
const hmac = crypto.createHmac('sha256', clientSecret).update(sourceString).digest('base64');
// Safe length check before performing constant-time comparison
const sigBuffer = Buffer.from(signature, 'utf-8');
const hmacBuffer = Buffer.from(hmac, 'utf-8');
if (sigBuffer.length !== hmacBuffer.length) return false;
return crypto.timingSafeEqual(hmacBuffer, sigBuffer);
}
Hardening Express Backend Infrastructure Against Cryptographic and Replay Attacks
When implementing production routes to verify hubspot webhook signature v3 nodejs endpoints, applying proper URL construction and buffer comparison safeguards your application infrastructure:
-
Capture Unparsed Payload Stream: Ensure Express body-parser rules retain the untouched
rawBodystream buffer before global JSON parsers transform key orders or whitespace. -
Store Signatures for Replay Protection: Cache verified
X-HubSpot-Signature-v3headers in Redis In-Memory Data Store using a 5-minute Time-To-Live (TTL) to block duplicate webhook executions. -
Avoid Base64 vs Hex Mismatches: Remember that HubSpot expects Base64 digest output (
.digest('base64')) rather than standard hex encoding. -
Prevent Timing Side-Channel Exploits: Utilize Node.js native crypto.timingSafeEqual Documentation against UTF-8 buffers to prevent timing side-channel attacks.
-
Account for Reverse Proxies: When running Express behind NGINX, Cloudflare, or AWS ALB, set
app.set('trust proxy', true)soreq.protocolandreq.get('host')accurately reflect the public HTTPS scheme.
Common Pitfalls When You Verify HubSpot Webhook Signature V3 Nodejs Scripts
Even experienced engineers run into configuration issues when validating HubSpot v3 event signatures:
-
Using the Wrong Token: Attempting to verify signatures using a Private App Access Token (
pat-na1...) instead of the actual Client Secret causes instant signature failure. -
Incomplete URL Concatenation: Omitting query parameters or hardcoding
http://instead ofhttps://during URL reconstruction creates string mismatch errors. -
Timestamp Unit Mismatch: Using seconds instead of milliseconds when calculating timestamp drift against
X-HubSpot-Request-Timestampinvalidates valid incoming requests. -
Ignoring Trailing Slashes: Ensure the endpoint URL set in HubSpot’s developer portal strictly matches the path configured in your Express router (e.g.,
/webhooks/hubspotvs/webhooks/hubspot/).
Debugging Webhook Workflows with WebhookIQ Utilities
If your HubSpot webhooks are getting rejected due to subtle URL path construction bugs or timestamp drift issues, you can inspect raw base64 digests and validate your payload structure in real time with HookDoc.
Check out our Webhook Testing Services page or read more technical articles on our Webhook Testing Blog to master webhooks security, schema validation, and real-time event debugging. When you test and verify hubspot webhook signature v3 nodejs handlers in a sandboxed testing environment, you eliminate signature rejection errors and maintain seamless CRM event delivery.
