'Verifying Qb notification signature in C#

I am trying to verify signature , I received from QB notification but always failing. Below is my function I made

 public static bool ValidateRequest(Dictionary<string, string> headers, string payload, string verifier)
        {
            string signature = headers["intuit-signature"];
            if ((signature == null))
            {
                return false;
            }

            try
            {
                byte[] secretKeyBArr = Encoding.UTF8.GetBytes(verifier);
                byte[] dataBytes = Encoding.UTF8.GetBytes(payload);

                HMACSHA256 hmacsha256 = new HMACSHA256();
                hmacsha256.Key = secretKeyBArr;
                hmacsha256.Initialize();
                byte[] hmacBytes = hmacsha256.ComputeHash(dataBytes);

                string hash = Convert.ToBase64String(hmacBytes);//Payload value
                return hash.Equals(signature);
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return false;
        }

Not sure why computed signature and received signature does not match all time.

Appreciate your inputs.



Solution 1:[1]

If your having the same issue I had, its because of the way I was serializing the payload. When QBO generates the signature, they use datetimes in the format 2022-05-11T15:11:58.000Z. I was serializing it as 2022-05-11T15:11:58Z

I considered 2 options

help with serialization:

public class QboChangeEventEntitiesVm
{
    [Required]
    [JsonProperty(PropertyName = "name")]
    public string? Name { get; set; }

    [Required]
    [JsonProperty(PropertyName = "id")]
    public string? Id { get; set; }

    [Required]
    [JsonConverter(typeof(StringEnumConverter))]
    [JsonProperty(PropertyName = "operation")]
    public QboOperationType? Operation { get; set; }

    [JsonConverter(typeof(DateFormatConverter), "yyyy-MM-dd'T'HH:mm:ss.fff'Z'")]
    [JsonProperty(PropertyName = "lastUpdated")]
    public DateTime? LastUpdated { get; set; }
}

public class DateFormatConverter : IsoDateTimeConverter
{
    public DateFormatConverter(string format)
    {
        DateTimeFormat = format;
    }
}

or just retrieve the raw bits

        string requestBody;
        using (var stream = new MemoryStream())
        {
            var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
            context.Request.InputStream.Seek(0, SeekOrigin.Begin);
            context.Request.InputStream.CopyTo(stream);
            requestBody = Encoding.UTF8.GetString(stream.ToArray());
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user3161312