Yes good point I do include it and still no dice…do you have it working?
Sorry, that was the first thing that stood out to me. I’m not familiar with .NET but your logic looks correct to me. I have it working in Node.js which I can clean up and post as an example here if that’d be helpful.
The string I’m concatening and hashing for a CRM card looks like:
GEThttps://XXX-XXX-XXX-XXX.ngrok.io/path/to/endpoint?userId=XXXXXXXX&userEmail=emailmaria@hubspot.com&associatedObjectId=1&associatedObjectType=CONTACT&portalId=XXXXXXXX1648664076585
Keep in mind, yours will look a little different depending on what’s in the request body for your webhook POST and if any query string parameters are being passed. I have no request body for a CRM card GET request:
portalId=XXXXXXXX<the request body would go here if there was one>1648664076585
I know I’m 2 years later, but anyway.
I did this and worked for me:
[HttpPost]public async Task<IActionResult> Webhook(){ var res = await ValidateRequest(HttpContext); return Ok(res);}private async Task<bool> ValidateRequest(HttpContext httpContext){ httpContext.Request.Headers.TryGetValue("X-Hubspot-Request-Timestamp", out var timeStamp); httpContext.Request.Headers.TryGetValue("X-Hubspot-Signature-V3", out var v3); var webHookUrl = $"{httpContext.Request.Scheme}://{httpContext.Request.Host}{httpContext.Request.Path}"; var fullWebhookUrl = new Uri(webHookUrl).AbsoluteUri; HMACSHA256 hashObject = new(Encoding.UTF8.GetBytes(_appSecret)); var payload = ""; using (var reader = new StreamReader(httpContext.Request.Body, leaveOpen: true)) { payload = await reader.ReadToEndAsync(); } var data = string.Concat(httpContext.Request.Method, fullWebhookUrl, payload, timeStamp); var utf = Encoding.UTF8.GetBytes(data); var signatureV3 = hashObject.ComputeHash(utf); var encodedSignature = Convert.ToBase64String(signatureV3); var validRequest = v3.Equals(encodedSignature); return validRequest;}
Those who are still struggling, please see https://stackoverflow.com/a/79162879/5375297
