# Having Trouble Validating Webhook

**URL:** <https://devforum.zoom.us/t/having-trouble-validating-webhook/80234>\
**Category:** API and Webhooks\
**Created:** [December 13, 2022, 5:42pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234 "2022-12-13T17:42:34Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ahavatammi](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/ahavatammi/32/33870_2.png) [@ahavatammi](https://devforum.zoom.us/u/ahavatammi)\
**Post date:** [December 13, 2022, 5:42pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/1 "2022-12-13T17:42:34Z")

</div>

Hi,

I’m trying to verify my webhook vai c# and it is not working. Can I please get some assistance on my code to see where I’m going wrong?

Thank you.

```
       log.Info("Recieved validation request");
        JObject joPayload = JObject.Parse(payload);
        var keySent = (string)joPayload.SelectToken("payload.plainToken");
        log.Info("Key Sent: " + keySent);

        string hashString = "";
        var secret = keySent;
        var message = keySent;
        var encoding = new System.Text.ASCIIEncoding();
        byte[] keyByte = encoding.GetBytes(secret);
        byte[] messageBytes = encoding.GetBytes(message);
        using (var hmacsha256 = new HMACSHA256(keyByte))
        {
            byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
            hashString = Convert.ToBase64String(hashmessage);
        }

        StringBuilder sb = new StringBuilder();
        foreach (char t in hashString)
        { 
            //Note: X for upper, x for lower case letters
            sb.Append(Convert.ToInt32(t).ToString("x2")); 
        }

        response = "{\"plainToken\": \"" + keySent +"\",\"encryptedToken\": \"" + hashString + "\"}";
        log.Info("Response: " + response);

```

---

<div class="post-metadata">

**Author:** ![elisa.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/elisa.zoom/32/47836_2.png) [@elisa.zoom](https://devforum.zoom.us/u/elisa.zoom)\
**Post date:** [December 19, 2022, 10:40pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/2 "2022-12-19T22:40:52Z")

</div>

Hi @ahavatammi  
Thanks for reaching out!  
Have you been able to troubleshoot this? or do you still need assistance here?  
I will take a look into this in the meantime!  
Best,  
Elisa

---

<div class="post-metadata">

**Author:** ![ahavatammi](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/ahavatammi/32/33870_2.png) [@ahavatammi](https://devforum.zoom.us/u/ahavatammi)\
**Post date:** [December 20, 2022, 2:01pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/3 "2022-12-20T14:01:06Z")

</div>

Hi Elisa,

Yes, can I please get some assistance? I have read many articles and still am unable to get this to work.

Thank you,  
Jeff

---

<div class="post-metadata">

**Author:** ![elisa.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/elisa.zoom/32/47836_2.png) [@elisa.zoom](https://devforum.zoom.us/u/elisa.zoom)\
**Post date:** [December 20, 2022, 7:43pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/4 "2022-12-20T19:43:42Z")

</div>

Hi @ahavatammi  
Here is a code snippet that might be helpful

```auto
const crypto = require('crypto')

const message = `v0:${request.headers['x-zm-request-timestamp']}:${JSON.stringify(request.body)}`

const hashForVerify = crypto.createHmac('sha256', ZOOM_WEBHOOK_SECRET_TOKEN).update(message).digest('hex')

const signature = `v0=${hashForVerify}`

if (request.headers['x-zm-signature'] === signature) {
  // Webhook request came from Zoom
} else {
  // Webhook request did not come from Zoom
}

```

And also the link to our sample app

> <https://github.com/zoom/webhook-sample-node.js/blob/master/index.js#L31>

Note how you would have to construct a message string first and then you would pass that message down to validate the URL

Hope this helps

---

<div class="post-metadata">

**Author:** ![ahavatammi](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/ahavatammi/32/33870_2.png) [@ahavatammi](https://devforum.zoom.us/u/ahavatammi)\
**Post date:** [December 21, 2022, 6:10pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/5 "2022-12-21T18:10:51Z")

</div>

Hi Elisa,

Thank you for the code sample.

I was able to figure it out with the help of [Free HMAC-SHA256 Online Generator Tool | Devglan](https://www.devglan.com/online-tools/hmac-sha256-online). I used it to the create the return value and then compare it to my code.

Here is a working example for those coming behind me.

```auto
        private static string UrlValidation(string sig, string tStamp, string payload, ILogger log)
        {

            log.LogInformation("Recieved validation request");

			// get the plainToken
            JObject joPayload = JObject.Parse(payload);
            var plainToken = (string)joPayload.SelectToken("payload.plainToken");
            log.LogInformation("plainToken: " + plainToken);

            // secret token from the marketplace app
            string secretToken = "<your token here>";

            string message = plainToken;
            
            // convert secret token to bytes
            byte[] secretTokenByte = new UTF8Encoding().GetBytes(secretToken);
            // convert the plainToken sent in to bytes
            byte[] messageBytes = new UTF8Encoding().GetBytes(message);
            // hash it
            byte[] hashmessage = new HMACSHA256(secretTokenByte).ComputeHash(messageBytes);
            // to lowercase hex
            string hexMessage = String.Concat(Array.ConvertAll(hashmessage, x => x.ToString("x2")));
            // create return message
            string response = "{\"plainToken\": \"" + plainToken + "\",\"encryptedToken\": \"" + hexMessage + "\"}";

            log.LogInformation("Response: " + response);

            return response;
        }

```

---

<div class="post-metadata">

**Author:** ![elisa.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/elisa.zoom/32/47836_2.png) [@elisa.zoom](https://devforum.zoom.us/u/elisa.zoom)\
**Post date:** [December 21, 2022, 6:27pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/6 "2022-12-21T18:27:46Z")

</div>

Hi @ahavatammi  
Thanks for sharing your findings with the community!  
Feel free to reach out back to us if you need anything else!  
Best,  
Elisa

---

<div class="post-metadata">

**Author:** ![mpzoomuser](https://avatars.discourse-cdn.com/v4/letter/m/f1d935/32.png) [@mpzoomuser](https://devforum.zoom.us/u/mpzoomuser)\
**Post date:** [June 22, 2023, 4:33pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/7 "2023-06-22T16:33:08Z")

</div>

I did try with UrlValidation function which is provided in the sample code, it returns the value which is not same as the `x-zm-signature` value. Am I missing anything?

---

<div class="post-metadata">

**Author:** ![mpzoomuser](https://avatars.discourse-cdn.com/v4/letter/m/f1d935/32.png) [@mpzoomuser](https://devforum.zoom.us/u/mpzoomuser)\
**Post date:** [June 26, 2023, 4:25pm UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/8 "2023-06-26T16:25:19Z")

</div>

@ahavatammi , I’m not seeing plainToken in the payload object. How did you get that value?

---

<div class="post-metadata">

**Author:** ![calixtogelarzo](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/calixtogelarzo/32/56822_2.png) [@calixtogelarzo](https://devforum.zoom.us/u/calixtogelarzo)\
**Post date:** [February 21, 2024, 11:41am UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/9 "2024-02-21T11:41:57Z")

</div>

Just to add, the response message should be serialize before passing it to the response. Below is my c# code sample that works

[HttpPost(“webhook”)]  
public IActionResult Post([FromBody] JObject body)  
{  
var response = new JObject();

```
Console.WriteLine(Request.Headers);
Console.WriteLine(body);

// Construct the message string
string timestamp = Request.Headers["x-zm-request-timestamp"];
string message = $"v0:{timestamp}:{JsonConvert.SerializeObject(body)}";
string hashForVerify = string.Empty;
string hashForValidate = string.Empty;

// Create a hash-based message authentication code (HMAC) using the SHA-256 hash function
using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes("ThisShouldBeYourSecretToken")))
{
    byte[] hashValue = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
    hashForVerify = BitConverter.ToString(hashValue).Replace("-", "").ToLower();
}

// Hash the message string with your Webhook Secret Token and prepend the version semantic
string signature = $"v0={hashForVerify}";

// Validate the request
if (Request.Headers["x-zm-signature"] == signature)
{
    // Zoom validating you control the webhook endpoint
    if (body["event"].ToString() == "endpoint.url_validation")
    {
        using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes("ThisShouldBeYourSecretToken")))
        {
            byte[] hashValue = hmac.ComputeHash(Encoding.UTF8.GetBytes(body["payload"]["plainToken"].ToString()));
            hashForValidate = BitConverter.ToString(hashValue).Replace("-", "").ToLower();
        }

        response["message"] = new JObject
        {
            { "plainToken", body["payload"]["plainToken"] },
            { "encryptedToken", hashForValidate }
        };
        response["status"] = 200;

        return Ok(JsonConvert.SerializeObject(response["message"]));
    }
    else
    {
        response["message"] = "Authorized request to Zoom Webhook sample.";
        response["status"] = 200;

        Console.WriteLine(response["message"]);

        // Business logic here, example make API request to Zoom or 3rd party

        return Ok(response);
    }
}
else
{
    response["message"] = "Unauthorized request to Zoom Webhook sample.";
    response["status"] = 401;

    Console.WriteLine(response["message"]);

    return Unauthorized(response);
}

```

}

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex016/uploads/zoomdeveloper/original/3X/6/1/614bdd549b610bbaa46ff934617683a02bdaa03c.png) [@system](https://devforum.zoom.us/u/system)\
**Post date:** [February 24, 2025, 3:18am UTC](https://devforum.zoom.us/t/having-trouble-validating-webhook/80234/10 "2025-02-24T03:18:54Z")

</div>

This topic was automatically closed 368 days after the last reply. New replies are no longer allowed.
