APIs & Integrations

keco39
Member

HubSpot Signature with .NET (C#)

SOLVE

Hi,

 

I'm currently having trouble to get the same 'request signature' as is provided by the http header 'X-HubSpot-Signature'. I'm using C# (.NET) for my development.

 

This is the information I receive and compute... The App ID is 187705.

 

HubSpot Request Signature: ad34f70f5c1c56dd529a7b21a2bfe479787956d8c7e90d576903a2bc79c6b844

 

Request Method: POST

Request Uri: https://dev-stone-ecommerce.natch.be/api/rootapi/checkhubspotsignature

Request Body: [{"eventId":1,"subscriptionId":98674,"portalId":5399955,"occurredAt":1548749689416,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":187705}]

 

Computed Request Signature: 7CB581CED2D6953181AD611AB0B46D7DF2DF2CBEC24A693E235E91C62C7CAB67

 

 

This is the method I use to hash the concatenated string of 'app secret', the 'request method', the 'request uri' and the 'request body'.

 

 

private static string EncryptToSHA256(string value)
        {
            var hashingMethod = new System.Security.Cryptography.SHA256Managed();
            var hashedByteArray = hashingMethod.ComputeHash(Encoding.UTF8.GetBytes(value));

            var hash = new StringBuilder();
            foreach (var byteValue in hashedByteArray)
            {
                hash.Append($"{byteValue:X2}");
            }

            return hash.ToString();
        }

 

Is there something I'm missing? Or someone with experience in the technology?

 

0 Upvotes
1 Accepted solution
cbarley
Solution
HubSpot Alumni
HubSpot Alumni

HubSpot Signature with .NET (C#)

SOLVE

Alright @keco39 , sorry about the confusion. Looks like for Webhooks, the validation method is different from the other APIs. As per this section in the Webhooks docs: 

 

we populate a X-HubSpot-Signature header with a SHA-256 hash of the concatenation of the app-secret for your application and the request body we're sending.

 

I used the following code which gave me the hash

ad34f70f5c1c56dd529a7b21a2bfe479787956d8c7e90d576903a2bc79c6b844

which is correct.

 

const {SHA256} = require("crypto-js");
const secret = "ea1b47cb-XXXX-XXXX-XXXX-XXXXXXXXXX";
const body = JSON.stringify([{"eventId":1,"subscriptionId":98674,"portalId":5399955,"occurredAt":1548749689416,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":187705}]);
const data = secret + body;

var hash = SHA256(data).toString();

console.log("=============");
console.log(hash);
console.log("=============");

 

We're working on moving our validation system for webhooks onto the same one as all the others and can definitely see how this was confusing!

View solution in original post

0 Upvotes
10 Replies 10
cbarley
HubSpot Alumni
HubSpot Alumni

HubSpot Signature with .NET (C#)

SOLVE

Hi @keco39 , happy to help here! Using your client secret, method, uri, and body, I was able to generate a hash using NodeJS that matches yours. When checking out your app, I'm seeing you paused the subscriptions. Is there any way you could unpause your subscriptions so I can see a HubSpot Request signature to make sure that I've got everything properly formatted? 

0 Upvotes
keco39
Member

HubSpot Signature with .NET (C#)

SOLVE

Thank you for the answer. As we use .NET (C#) and not node.js, I'm wondering if it has anything to do with the way the SHA256 hashing is calculated. Do you have to specify an encoding within node.js, as I've seen examples with ascii and utf-8 but most of the people tell utf-8 is the type to choose and that's what I have done.

 

I hope I can find someone with a .NET example for this as it's quite crucial for a client of ours (Stoneasy).

 

I activated the 2 subscriptions...

 

Kind regards,

Kevin Cocquyt

0 Upvotes
cbarley
HubSpot Alumni
HubSpot Alumni

HubSpot Signature with .NET (C#)

SOLVE

Hi @keco39 , thanks for that. I'm not able to get the test of your webhook URL to work as it doesn't look like your app is installed in any portal. You don't have to specify encoding with Node.JS, but it defaults to utf-8. I don't have an example of this, but maybe somebody else from the community might?

 

I did happen to find this example from Microsoft: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.sha256?view=netframework-4.... which could help

0 Upvotes
keco39
Member

HubSpot Signature with .NET (C#)

SOLVE

I must clearly be doing something wrong. I tested the same code in node.js and came up with the same hash... 😞

 

This is what I'm doing...

 

const crypto = require("crypto");
const hash = crypto.createHash("sha256");

hash.on("readable", () => {
    const data = hash.read();
    if (data) {
        console.log(data.toString("hex"));
    }
});

const appSecret = "ea1b47cb-XXXX-XXXX-XXXX-3b8098382e91";
const requestMethod = "POST";
const requestUri = "https://dev-stone-ecommerce.natch.be/api/rootapi/checkhubspotsignature";
const requestBody = "[{\"eventId\":1,\"subscriptionId\":98674,\"portalId\":5399955,\"occurredAt\":1548749689416,\"subscriptionType\":\"contact.creation\",\"attemptNumber\":0,\"objectId\":123,\"changeSource\":\"CRM\",\"changeFlag\":\"NEW\",\"appId\":187705}]";

const someData = `${appSecret}${requestMethod}${requestUri}${requestBody}`;

hash.write(someData);
hash.end();

 

I obfuscated my client secret but I guess you could reach for it using the app settings.

 

The signature I receive is "ad34f70f5c1c56dd529a7b21a2bfe479787956d8c7e90d576903a2bc79c6b844" whilst the computed one is "7cb581ced2d6953181ad611ab0b46d7df2df2cbec24a693e235e91c62c7cab67" (the same as doing it in .NET).

 

Thank you for your time!

0 Upvotes
keco39
Member

HubSpot Signature with .NET (C#)

SOLVE

If someone could help me out... This might be more important to the issue at hand...

 

I'm reading the body as follows (in .NET that is)...

 

var requestBody = filterContext.Request.Content.ReadAsStringAsync().Result;

 

I also tried with the following but, whilst giving a different signature after hashing than the statement above, still is not the same as the one given by HubSpot...

 

var requestBody = HttpUtility.UrlEncode(filterContext.Request.Content.ReadAsByteArrayAsync().Result);

 

The last statement was influenced by another post on this forum (https://community.hubspot.com/t5/APIs-Integrations/CRM-Extension-Request-Signature/m-p/240139).

 

0 Upvotes
cbarley
HubSpot Alumni
HubSpot Alumni

HubSpot Signature with .NET (C#)

SOLVE

Hey @keco39 , I'm reaching out to my team at the moment about this. I'm still not able to get the right hash either. My code is as follows:

 

const {SHA256} = require("crypto-js");
const secret = "ea1b47cb-XXX-XXX-XXX-XXXXXXXXXXX";
const method = "POST";
const URI = "https://dev-stone-ecommerce.natch.be/api/rootapi/checkhubspotsignature";
const body = JSON.stringify([{"eventId":1,"subscriptionId":98674,"portalId":5399955,"occurredAt":1548749689416,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":187705}]);
const data = secret + method + URI + body;

var hash = SHA256(data).toString();

// console.log(data);
console.log("=============");
console.log(data);
console.log(hash);
console.log("=============");

I get returned the hash 

7cb581ced2d6953181ad611ab0b46d7df2df2cbec24a693e235e91c62c7cab67

 

I'm wondering if there's anything that we're missing from the documentation, or if there's anything we're both doing wrong. I'll reach back out when I have more info. Thanks so much!

0 Upvotes
cbarley
Solution
HubSpot Alumni
HubSpot Alumni

HubSpot Signature with .NET (C#)

SOLVE

Alright @keco39 , sorry about the confusion. Looks like for Webhooks, the validation method is different from the other APIs. As per this section in the Webhooks docs: 

 

we populate a X-HubSpot-Signature header with a SHA-256 hash of the concatenation of the app-secret for your application and the request body we're sending.

 

I used the following code which gave me the hash

ad34f70f5c1c56dd529a7b21a2bfe479787956d8c7e90d576903a2bc79c6b844

which is correct.

 

const {SHA256} = require("crypto-js");
const secret = "ea1b47cb-XXXX-XXXX-XXXX-XXXXXXXXXX";
const body = JSON.stringify([{"eventId":1,"subscriptionId":98674,"portalId":5399955,"occurredAt":1548749689416,"subscriptionType":"contact.creation","attemptNumber":0,"objectId":123,"changeSource":"CRM","changeFlag":"NEW","appId":187705}]);
const data = secret + body;

var hash = SHA256(data).toString();

console.log("=============");
console.log(hash);
console.log("=============");

 

We're working on moving our validation system for webhooks onto the same one as all the others and can definitely see how this was confusing!

0 Upvotes
keco39
Member

HubSpot Signature with .NET (C#)

SOLVE

Nice! It works now, thank you for your help (and patience).

 

The link to the docs we were using came from an e-mail we received from HubSpot, telling us about the permanent switch from basic authentication and in that mail was a link to the docs (with the concatenation of the 4 values). Might be interesting to check the content of that email.

0 Upvotes
SnowMountainJC
Member

HubSpot Signature with .NET (C#)

SOLVE

Hey Keco, What exactly ended up being your final implementation in your .Net code for this?  I am running into a very similar issue where I don't have my .NET SHA256 Hashes matching either and it really seems like it should be.

I am currently using SHA256 managed to hash a string that is the client secret and the message body concatenated. Did you find you had to do anything other than that?

0 Upvotes
keco39
Member

HubSpot Signature with .NET (C#)

SOLVE

The best way I can help you out is sharing the filter I'm currently using in my .NET project. I created a github repo and put the filter in there: https://github.com/KevinCocquyt39/hubspot/blob/master/AuthorizeHubSpotAttribute.cs. I use that filter as an attribute on the API that is receiving the request from the webhook configured within HubSpot.

 

Because there are 3 ways to create a signature yourself, I'm using the one for CRM extensions but I kept the other ones in there for future reference (+ a link to the official docs).

 

Make sure your environment isn't reverse proxied as in our case (https offloading) as I also lost some time before I knew what the issue was.

0 Upvotes