# Help with authenticating webhook signature

**URL:** https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989
**Category:** API
**Tags:** webhook
**Created:** [September 17, 2020, 8:04pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989 "2020-09-17T20:04:55Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![jhnbkr](https://avatars.discourse-cdn.com/v4/letter/j/3e96dc/32.png) [@jhnbkr](https://community.sendbird.com/u/jhnbkr)
#### Post date: [September 17, 2020, 8:04pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/1 "2020-09-17T20:04:55Z")

</div>

I am having some issues generating a signature that matches the `x-sendbird-signature` header of a webhook request. The [webhook documentation](https://docs.sendbird.com/platform/webhooks) is being used as reference. Hopefully another set of eyes can help resolve this.

Our service is written in Python 3.8 (Django) and we are using Django Rest Framework (DRF) to process the webhook requests.

Note, some of the contents of this post were redacted and the examples provided are from a testing application using mocked data.

* * *

[Beeceptor](https://beeceptor.com/) is being used to capture webhook requests from our test application. The following is an example of a webhook request.

##### Headers

```auto
{
  "content-length": "1897",
  "accept-encoding": "gzip, deflate",
  "accept": "*/*",
  "user-agent": "SendBird",
  "x-signature": "16e3cb25eea601c7a211e5a52d91fa1a31afdd33cc2a2ac5f248ea45189efb26",
  "content-type": "application/json",
  "unicode-escaped": "true",
  "x-sendbird-signature": "16e3cb25eea601c7a211e5a52d91fa1a31afdd33cc2a2ac5f248ea45189efb26"
}

```

##### Response

```auto
{"category":"group_channel:message_send","sender":{"nickname":"john","user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}},"silent":false,"custom_type":"","mention_type":"users","mentioned_users":[],"app_id":"9BDF228D-8E32-43DE-88B7-969BA4CF4C40","sender_ip_addr":"99.231.147.50","members":[{"is_blocking_sender":false,"unread_message_count":7,"total_unread_message_count":7,"is_active":true,"is_online":true,"is_hidden":0,"channel_mention_count":0,"nickname":"john","is_blocked_by_sender":false,"user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","channel_unread_message_count":2,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}},{"is_blocking_sender":false,"unread_message_count":8,"total_unread_message_count":8,"is_active":true,"is_online":true,"is_hidden":0,"channel_mention_count":0,"nickname":"youngastro","is_blocked_by_sender":false,"user_id":"6349077a-833a-4eda-bffd-8fc1381ae6f9","channel_unread_message_count":3,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/b88eff9a-7d01-43ef-8397-d8384c0eab5c\/earth.gif","metadata":{"full_name":"Young Astronaut"}}],"type":"MESG","payload":{"custom_type":"","created_at":1600368905025,"translations":{},"message":"g\n","data":"","message_id":7470735177},"channel":{"is_distinct":true,"name":"a6571743-7093-4d44-8ef9-32130833a930","custom_type":"private","is_ephemeral":false,"channel_url":"eb823739-c8c8-42ee-a078-5b53e47283b7","is_public":false,"is_super":false,"data":"","is_discoverable":false},"sdk":"JavaScript"}

```

* * *

DRF provides conveniences for handling requests, such as properties for the request byte array and parsed data, so the following script was written to eliminate any characteristics of the framework.

##### Source

```auto
import hashlib
import hmac

x_sendbird_signature = "16e3cb25eea601c7a211e5a52d91fa1a31afdd33cc2a2ac5f248ea45189efb26"
payload = '{"category":"group_channel:message_send","sender":{"nickname":"john","user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}},"silent":false,"custom_type":"","mention_type":"users","mentioned_users":[],"app_id":"9BDF228D-8E32-43DE-88B7-969BA4CF4C40","sender_ip_addr":"99.231.147.50","members":[{"is_blocking_sender":false,"unread_message_count":7,"total_unread_message_count":7,"is_active":true,"is_online":true,"is_hidden":0,"channel_mention_count":0,"nickname":"john","is_blocked_by_sender":false,"user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","channel_unread_message_count":2,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}},{"is_blocking_sender":false,"unread_message_count":8,"total_unread_message_count":8,"is_active":true,"is_online":true,"is_hidden":0,"channel_mention_count":0,"nickname":"youngastro","is_blocked_by_sender":false,"user_id":"6349077a-833a-4eda-bffd-8fc1381ae6f9","channel_unread_message_count":3,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/b88eff9a-7d01-43ef-8397-d8384c0eab5c\/earth.gif","metadata":{"full_name":"Young Astronaut"}}],"type":"MESG","payload":{"custom_type":"","created_at":1600368905025,"translations":{},"message":"g\n","data":"","message_id":7470735177},"channel":{"is_distinct":true,"name":"a6571743-7093-4d44-8ef9-32130833a930","custom_type":"private","is_ephemeral":false,"channel_url":"eb823739-c8c8-42ee-a078-5b53e47283b7","is_public":false,"is_super":false,"data":"","is_discoverable":false},"sdk":"JavaScript"}'

signature = hmac.new(
    key=b'REDACTED',
    msg=bytes(payload.encode('utf8')),
    digestmod=hashlib.sha256,
).hexdigest()

print(signature, x_sendbird_signature)
assert (signature==x_sendbird_signature)

```

##### Output

```auto
/REDACTED/venv/bin/python "/REDACTED/sendbird_signature_test.py"
37d8f06f0ab8ee163c7d3f3810816f62d78b19fdcdcf5fab0ebadfaf8970bd2e 16e3cb25eea601c7a211e5a52d91fa1a31afdd33cc2a2ac5f248ea45189efb26
Traceback (most recent call last):
  File "/REDACTED/sendbird_signature_test.py", line 14, in <module>
    assert (signature==x_sendbird_signature)
AssertionError

```

The documentation is not clear which API token I should use. I have tried with the master and several others generated in the dashboard. It’s not clear which token the server uses to generated the hash. I don’t see any options to specify a token for the webhook. I even tried using the application ID.

* * *

I have tried several different ways of encoding the key and message, several different webhook requests, and different ways of interpreting the JSON response (such as encoding to Python dict, dumping back to a string, encoding, and casting to byte array). I also tried capturing a webhook example directly from our staging server, and another request interceptor service.

Any assistance would be greatly appreciated. Thank you.

---

<div class="post-metadata">

### Author: ![Jason](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/jason/32/488_2.png) [@Jason](https://community.sendbird.com/u/Jason)
#### Post date: [September 17, 2020, 10:33pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/2 "2020-09-17T22:33:36Z")

</div>

@jhnbkr

Thank you so much for the detailed post. Please note that only the master API token can be used for authenticating `x-sendbird-signature`.

Other than that, your code looks okay. I did find that your sample decodes as expected in a node.js environment but not in Python3. I will ask our engineers to take a look.

---

<div class="post-metadata">

### Author: ![jhnbkr](https://avatars.discourse-cdn.com/v4/letter/j/3e96dc/32.png) [@jhnbkr](https://community.sendbird.com/u/jhnbkr)
#### Post date: [September 17, 2020, 11:24pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/3 "2020-09-17T23:24:00Z")

</div>

@Jason thanks for the response. That’s good to know it has to be our master token. I may suggest adding that to the documentation.

I am still not seeing the expected results when using the master token in Python3. I did try a variant in node (with the master token) and the results did not match either.

#### Source

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

const SENDBIRD_API_TOKEN = 'REDACTED';
const body = '{"category":"group_channel:message_send","sender":{"nickname":"john","user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}},"silent":false,"custom_type":"","mention_type":"users","mentioned_users":[],"app_id":"9BDF228D-8E32-43DE-88B7-969BA4CF4C40","sender_ip_addr":"99.231.147.50","members":[{"is_blocking_sender":false,"unread_message_count":11,"total_unread_message_count":11,"is_active":true,"is_online":false,"is_hidden":0,"channel_mention_count":0,"nickname":"youngastro","is_blocked_by_sender":false,"user_id":"6349077a-833a-4eda-bffd-8fc1381ae6f9","channel_unread_message_count":6,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/b88eff9a-7d01-43ef-8397-d8384c0eab5c\/earth.gif","metadata":{"full_name":"Young Astronaut"}},{"is_blocking_sender":false,"unread_message_count":7,"total_unread_message_count":7,"is_active":true,"is_online":true,"is_hidden":0,"channel_mention_count":0,"nickname":"john","is_blocked_by_sender":false,"user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","channel_unread_message_count":2,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}}],"type":"MESG","payload":{"custom_type":"","created_at":1600384455890,"translations":{},"message":"j\n","data":"","message_id":7474767628},"channel":{"is_distinct":true,"name":"a6571743-7093-4d44-8ef9-32130833a930","custom_type":"private","is_ephemeral":false,"channel_url":"eb823739-c8c8-42ee-a078-5b53e47283b7","is_public":false,"is_super":false,"data":"","is_discoverable":false},"sdk":"JavaScript"}'
const signature = 'd73661b11de84a3e3f9ddea30c0bbb678910d4fecaff92d24713456c13178929';
const hash = crypto
    .createHmac('sha256', SENDBIRD_API_TOKEN)
    .update(body)
    .digest('hex');

console.log(hash, signature)
console.assert(hash == signature)

```

#### Output

```auto
33ccb7af456501fcba477bff967b3752729b979892b6d57d8cf51f3af344cc6d d73661b11de84a3e3f9ddea30c0bbb678910d4fecaff92d24713456c13178929
Assertion failed

```

Would it be helpful to reach out via email and share our account information so someone from SendBird can test/investigate?

---

<div class="post-metadata">

### Author: ![Jason](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/jason/32/488_2.png) [@Jason](https://community.sendbird.com/u/Jason)
#### Post date: [September 17, 2020, 11:45pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/4 "2020-09-17T23:45:08Z")

</div>

@jhnbkr

For node.js there is one small tweak needed. In the code below I JSON stringify the body as a JSON object and strip out the escaping characters.

`JSON.stringify(body).replace(/\//g, '\\/')`;

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

const SENDBIRD_API_TOKEN = 'REDACTED';
const body = {"category":"group_channel:message_send","sender":{"nickname":"john","user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}},"silent":false,"custom_type":"","mention_type":"users","mentioned_users":[],"app_id":"9BDF228D-8E32-43DE-88B7-969BA4CF4C40","sender_ip_addr":"99.231.147.50","members":[{"is_blocking_sender":false,"unread_message_count":11,"total_unread_message_count":11,"is_active":true,"is_online":false,"is_hidden":0,"channel_mention_count":0,"nickname":"youngastro","is_blocked_by_sender":false,"user_id":"6349077a-833a-4eda-bffd-8fc1381ae6f9","channel_unread_message_count":6,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/b88eff9a-7d01-43ef-8397-d8384c0eab5c\/earth.gif","metadata":{"full_name":"Young Astronaut"}},{"is_blocking_sender":false,"unread_message_count":7,"total_unread_message_count":7,"is_active":true,"is_online":true,"is_hidden":0,"channel_mention_count":0,"nickname":"john","is_blocked_by_sender":false,"user_id":"f6dc589f-bcdb-48d5-8848-d8d60e4cba5b","channel_unread_message_count":2,"state":"joined","push_enabled":true,"push_trigger_option":true,"profile_url":"https:\/\/storyplace-stage.s3.amazonaws.com\/asset\/image\/3047f6c2-2d6e-4ab3-a049-07aef47cd170\/pixel_john.jpg","metadata":{"full_name":"John Baker"}}],"type":"MESG","payload":{"custom_type":"","created_at":1600384455890,"translations":{},"message":"j\n","data":"","message_id":7474767628},"channel":{"is_distinct":true,"name":"a6571743-7093-4d44-8ef9-32130833a930","custom_type":"private","is_ephemeral":false,"channel_url":"eb823739-c8c8-42ee-a078-5b53e47283b7","is_public":false,"is_super":false,"data":"","is_discoverable":false},"sdk":"JavaScript"}
//Body is stringifyed and forward slashes are unescaped
body = JSON.stringify(body).replace(/\//g, '\\/'); 
const signature = 'd73661b11de84a3e3f9ddea30c0bbb678910d4fecaff92d24713456c13178929';

const hash = crypto
    .createHmac('sha256', SENDBIRD_API_TOKEN)
    .update(body)
    .digest('hex');

console.log(hash, signature)
console.assert(hash == signature)
```

---

<div class="post-metadata">

### Author: ![Jason](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/jason/32/488_2.png) [@Jason](https://community.sendbird.com/u/Jason)
#### Post date: [September 19, 2020, 3:41am UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/5 "2020-09-19T03:41:01Z")

</div>

@jhnbkr

The problem appears to be because of escape characters in the message (specifically, the message field of the web-hook is the message `g\n` so you need to hash the escaped version `g\\n` not the literal `g\n` ).

In your Python script please try `payload = r'{"category"... ` instead of `payload = {"category...`

---

<div class="post-metadata">

### Author: ![LukeMcS](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/lukemcs/32/825_2.png) [@LukeMcS](https://community.sendbird.com/u/LukeMcS)
#### Post date: [January 15, 2021, 3:38pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/6 "2021-01-15T15:38:16Z")

</div>

Thanks for this @Jason - Solved the issue for me. Could the documents be updated:

> **[Webhooks | Chat Platform API | Sendbird Docs](https://sendbird.com/docs/chat/v3/platform-api/guides/webhooks)**
>
> Learn about the configuration and requirements to retrieve Webhook events for Chat.

Wasted a bit of time trying to get this to work before I found your post. Both, that you must use the master and that the body must be tidied up before stringifying.

Thanks again for your solution 🙂

---

<div class="post-metadata">

### Author: ![Sameer\_Madan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/sameer_madan/32/693_2.png) [@Sameer\_Madan](https://community.sendbird.com/u/Sameer_Madan)
#### Post date: [July 21, 2021, 4:57pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/7 "2021-07-21T16:57:37Z")

</div>

Hi! Please update your docs to include this: [Webhooks | Chat Platform API | Sendbird Docs](https://sendbird.com/docs/chat/v3/platform-api/guides/webhooks#2-headers-3-x-sendbird-signature). I wasted so many hours on this which would have been saved if this was documented there.

Also, replace(///g, ‘\/’). You’re actually _escaping_ forward slashes, not _stripping out_ the escape characters, right?

```auto
'https://www.google.com'.replace(/\//g, '\\/')
> "https:\/\/www.google.com"

```

---

<div class="post-metadata">

### Author: ![Tyler](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/tyler/32/810_2.png) [@Tyler](https://community.sendbird.com/u/Tyler)
#### Post date: [July 22, 2021, 12:55pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/8 "2021-07-22T12:55:52Z")

</div>

Hi Sameer,

If you take in the request as text instead of converting it to JSON, there are no extra steps needed to validate the signature.

They key here is to use

```auto
app.use(express.text({ type: 'json' }));

```

After that, it works as is with:

```auto
const body = req.body;
  const signature = req.header('x-sendbird-signature');
  const hash = crypto.createHmac('sha256', token).update(body).digest('hex');

  if (signature == hash) {
    req.body = JSON.parse(req.body);
    next();
  } else {
    res.sendStatus(401);
  }

```

This is follows how our docs outline utilizing signature validation for Javascript.

---

<div class="post-metadata">

### Author: ![Sameer\_Madan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/sameer_madan/32/693_2.png) [@Sameer\_Madan](https://community.sendbird.com/u/Sameer_Madan)
#### Post date: [July 22, 2021, 7:37pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/9 "2021-07-22T19:37:58Z")

</div>

I’m using Firebase which just hands me req.body. Maybe there’s a way to configure it to request as text but I don’t see it - [Call functions via HTTP requests &nbsp;|&nbsp; Firebase](https://firebase.google.com/docs/functions/http-events).

---

<div class="post-metadata">

### Author: ![Tyler](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/tyler/32/810_2.png) [@Tyler](https://community.sendbird.com/u/Tyler)
#### Post date: [July 22, 2021, 7:47pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/10 "2021-07-22T19:47:12Z")

</div>

I see. Thank you for that clarification. I think that adds a bit to the confusion because you have a lot less control from Firebase’s side. I’ll talk with our Engineering team to see if we can formulate a way to rework our documentation to try and clear up some of the information there.

---

<div class="post-metadata">

### Author: ![Tyler](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/tyler/32/810_2.png) [@Tyler](https://community.sendbird.com/u/Tyler)
#### Post date: [July 22, 2021, 7:51pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/11 "2021-07-22T19:51:58Z")

</div>

@Sameer_Madan, I do see Firebase does allow you to implement your own express application. I’m not saying that is the solution in this case but something to think about.  
[https://firebase.google.com/docs/functions/http-events#using\_existing\_express\_apps](https://firebase.google.com/docs/functions/http-events#using_existing_express_apps)

---

<div class="post-metadata">

### Author: ![Kagan\_Kaptan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/kagan_kaptan/32/4699_2.png) [@Kagan\_Kaptan](https://community.sendbird.com/u/Kagan_Kaptan)
#### Post date: [November 16, 2023, 10:08am UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/13 "2023-11-16T10:08:08Z")

</div>

Hi,

I’m trying to do this with .net, but I can’t match the signatures in any way. I am using the Newtonsoft.Json library. Probably somehow it cannot format the payload correctly.

Do you have an example that I can provide this with .net?

---

<div class="post-metadata">

### Author: ![scottpatrickwright](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/scottpatrickwright/32/4728_2.png) [@scottpatrickwright](https://community.sendbird.com/u/scottpatrickwright)
#### Post date: [November 24, 2023, 3:21pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/14 "2023-11-24T15:21:44Z")

</div>

Please update your docs with the advice to replace escape characters. I assume this is fine in all situations. This is a confusing time hole for any dev trying to use your webhooks to fall into. My comments appears to come years later. The addition of the `.replace(/\//g, '\\/');` would take a few minutes to update and save over many devs and years many many fold that in lost time and annoyance.

---

<div class="post-metadata">

### Author: ![Tyler](https://sea2.discourse-cdn.com/flex020/user_avatar/community.sendbird.com/tyler/32/810_2.png) [@Tyler](https://community.sendbird.com/u/Tyler)
#### Post date: [November 25, 2023, 3:35pm UTC](https://community.sendbird.com/t/help-with-authenticating-webhook-signature/989/15 "2023-11-25T15:35:44Z")

</div>

Hello @scottpatrickwright ,

Im unsure how regex replace is relevant to this thread. Can you help me understand? This thread is related to webhook validation which does not relate to regex.
