# Webhook Secret issue

**URL:** https://meta.discourse.org/t/webhook-secret-issue/275909
**Category:** Support
**Tags:** webhooks
**Created:** [August 20, 2023, 9:30am UTC](https://meta.discourse.org/t/webhook-secret-issue/275909 "2023-08-20T09:30:32Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![Ben\_Sutton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ben_sutton/32/313156_2.png) [@Ben\_Sutton](https://meta.discourse.org/u/Ben_Sutton)
#### Post date: [August 20, 2023, 9:30am UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/1 "2023-08-20T09:30:32Z")

</div>

Hoping someone can tell me what I’m doing wrong here.

I’ve set up a Discourse Webhook and it works as expected **without a Secret**. I then write a _string_ into the Secret, and then copy that string into the receiving Webhook as a Header, like so:

```plaintext
X-Discourse-Event-Signature: secret_here

```

This produces the following error in the Body when the sending webhook is sent:

`{"code":"rest_forbidden","message":"Sorry, you are not allowed to do that.","data":{"status":401}}`

I expect that I’m just not doing it right, so please enlighten me!

I’m aware that the secret is encrypted using sha256, so the Header that is sent is:

```plaintext
X-Discourse-Event-Signature: sha256=XXX

```

But I’m not sure what I should be doing with this information in the receiving Webhook Security Headers.

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [August 20, 2023, 9:46am UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/2 "2023-08-20T09:46:38Z")

</div>

> [@Ben\_Sutton](#):
>
> ```plaintext
> Name: X-Discourse-Event-Signature
> Value: sha256=XXX
> 
> ```

I’m not sure if this is just the way you are writing the post but the actual header would be

`X-Discourse-Event-Signature: XXX`

You can (optionally) use this at the receiving end to validate that the webhook was actually sent by Discourse. If you don’t do the verification then a malicious party could potentially forge webhook events.

> [@Ben\_Sutton](#):
>
> copy that same string into the destination Webhook as a Header

What does this mean?

---

<div class="post-metadata">

### Author: ![Ben\_Sutton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ben_sutton/32/313156_2.png) [@Ben\_Sutton](https://meta.discourse.org/u/Ben_Sutton)
#### Post date: [August 20, 2023, 10:44am UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/3 "2023-08-20T10:44:16Z")

</div>

So you are suggesting that the Signature in the receiving webhook should be the encrypted secret, NOT the unencrypted chosen secret?

I am indeed writing the Header in the receiving application like so:  
`X-Discourse-Event-Signature: XXX`

I keep getting a 401 forbidden error though when I am using a Secret.

 ![CleanShot 2023-08-20 at 12.41.40@2x](https://global.discourse-cdn.com/meta/original/4X/f/f/f/fffe5eea966c473b3c1d7a917771225670ff74fb.png)

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [August 20, 2023, 12:22pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/4 "2023-08-20T12:22:20Z")

</div>

Where is that screenshot from?  
Maybe you can elaborate a bit more about your setup.

---

<div class="post-metadata">

### Author: ![Ben\_Sutton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ben_sutton/32/313156_2.png) [@Ben\_Sutton](https://meta.discourse.org/u/Ben_Sutton)
#### Post date: [August 20, 2023, 12:38pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/5 "2023-08-20T12:38:22Z")

</div>

My Wordpress website. I’m using a Wordpress Plugin to receive Webhooks. If I do not add a Security Header (Secret), the Webhook works fine. It’s only when I add the secret that the problem occurs.

Here’s the plugin: [https://automatorplugin.com/knowledge-base/webhook-triggers/](https://automatorplugin.com/knowledge-base/webhook-triggers/)

Thanks for your time Richard!

---

<div class="post-metadata">

### Author: ![Ben\_Sutton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ben_sutton/32/313156_2.png) [@Ben\_Sutton](https://meta.discourse.org/u/Ben_Sutton)
#### Post date: [August 20, 2023, 2:50pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/6 "2023-08-20T14:50:56Z")

</div>

I’ve since narrowed down the problem:

> Custom security headers may be included in the incoming webhook trigger, but one important note is how WordPress can change dashes to underscores. As an example, trying to use “x-api-key” may require using “x\_api\_key” instead.

I do however have a related question though @RGJ . Let’s say my secret is “1234”. In the receiving webhook, should the `X-Discourse-Event-Signature` value be:

1. 1234;
2. sha256=encrypted\_value\_here;
3. encrypted\_value\_here

?

---

<div class="post-metadata">

### Author: ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)
#### Post date: [August 20, 2023, 3:32pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/7 "2023-08-20T15:32:00Z")

</div>

It’s #2, `sha256=XXX`.

It looks like the Wordpress plugin you’re using can only compare against a static header value, not a dynamic signature. This is something Discourse specific.

---

<div class="post-metadata">

### Author: ![simon](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon/32/339122_2.png) [@simon](https://meta.discourse.org/u/simon)
#### Post date: [August 20, 2023, 3:58pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/8 "2023-08-20T15:58:22Z")

</div>

> [@Ben\_Sutton](#):
>
> I’m not sure what I should be doing with this information in the receiving Webhook Security Headers.

Have a look at how the [WP Discourse](https://github.com/discourse/wp-discourse) plugin handles the secret:

> <https://github.com/discourse/wp-discourse/blob/e2657990a3fd8e8f0076850418b184d19e1576dc/lib/plugin-utilities.php#L654-L669>

---

<div class="post-metadata">

### Author: ![Ben\_Sutton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ben_sutton/32/313156_2.png) [@Ben\_Sutton](https://meta.discourse.org/u/Ben_Sutton)
#### Post date: [August 20, 2023, 5:46pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/9 "2023-08-20T17:46:31Z")

</div>

I’ve since discovered that the sha value changes every time the webhook is sent, so putting the sha value in the receiving webhook would not work. I would think it would have to be example #1, and as I think you’re suggesting (re-static header), the plugin would actually need to decode the hash before generating the header response?

In conclusion, I don’t think I can use the hashed `X-Discourse-Event-Signature` in this plugin, because it will only accept static values.

Is it unsafe to use a webhook without a Secret? I would be sending User Events from my Discourse to my main website, using a non-obvious url such as `main-site.com/wp-json/fol/fil/532563-5312534` . I can also add static headers that must match on the receiving hook.

Could you give me an example of an application that could handle a dynamically changing hmac ?

---

<div class="post-metadata">

### Author: ![simon](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon/32/339122_2.png) [@simon](https://meta.discourse.org/u/simon)
#### Post date: [August 20, 2023, 8:43pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/10 "2023-08-20T20:43:17Z")

</div>

> [@Ben\_Sutton](#):
>
> I’ve since discovered that the sha value changes every time the webhook is sent,

The value is calculated against the webhook’s payload, so it’s going to be different for every request.

> [@Ben\_Sutton](#):
>
> Could you give me an example of an application that could handle a dynamically changing hmac ?

That’s an interesting question. The only application I know of is the [WP Discourse](https://github.com/discourse/wp-discourse) plugin, but it was configured specifically to handle Discourse webhooks. If Discourse’s implementation is preventing people from validating webhooks with secrets, maybe that needs to be looked into.

> [@Ben\_Sutton](#):
>
> Is it unsafe to use a webhook without a Secret?

I’ll leave that for others to answer.

If you are concerned about not validating the webhook, maybe the Incoming Webhook Triggers plugin has an action hook in its webhook receiving code that’s fired before the webhook’s data is processed. If it does, it should be possible to write a function that hooks into it, checks to see if the data is for a Discourse webhook, then validates the secret with something like the code I linked to in my previous post.

---

<div class="post-metadata">

### Author: ![simon](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon/32/339122_2.png) [@simon](https://meta.discourse.org/u/simon)
#### Post date: [August 21, 2023, 2:55pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/11 "2023-08-21T14:55:49Z")

</div>

> [@Ben\_Sutton](#):
>
> Could you give me an example of an application that could handle a dynamically changing hmac ?

I was curious, so I looked into this a bit. I’m unsure about applications that are configured to handle _receiving_ a dynamically changing HMAC signature, but authenticating webhook requests with a HMAC signature that’s calculated against the payload is a fairly standard practice for applications that are _sending_ webhooks. For example, GitHub, Stripe, and Shopify all use this method.

There are also quite a few popular applications that use the secret token method of authenticating webhooks. For example (as of 2021) Mailchimp, Trello, Slack, and Discord all use this approach. It seems that Slack is still using this method: [Slack developer FAQ | Slack Developer Docs](https://api.slack.com/faq#authenticate-servers). I can see how that would make things easier for the application that receives the webhook.

I guess there’s a trade off between security and convenience in terms of deciding which method the sending application will use. My concern with Discourse’s HMAC signature method is that it might result in people configuring webhooks without secret keys in order to get around the difficulty of handling the changing HMAC signatures. For example, there are a few references on Meta for sending Discourse webhooks to Zapier without any mention of how to validate the signature on Zapier. (It should be technically possible to validate the signatures on Zapier though. I’m not setup to test that at the moment.)

---

<div class="post-metadata">

### Author: ![Ben\_Sutton](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ben_sutton/32/313156_2.png) [@Ben\_Sutton](https://meta.discourse.org/u/Ben_Sutton)
#### Post date: [August 21, 2023, 4:23pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/12 "2023-08-21T16:23:48Z")

</div>

> [@simon](#):
>
> I guess there’s a trade off between security and convenience in terms of deciding which method the sending application will use. My concern with Discourse’s HMAC signature method is that it might result in people configuring webhooks without secret keys in order to get around the difficulty of handling the changing HMAC signatures. For example, there are a few references on Meta for sending Discourse webhooks to Zapier without any mention of how to validate the signature on Zapier. (It should be technically possible to validate the signatures on Zapier though. I’m not setup to test that at the moment.)

I absolutely agree with this. Perhaps this is something that the developers can explore - an easier and more compatible method of securing webhook data.

Also I’m not so sure that Zapier is even capable of validating the signature.

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [August 21, 2023, 4:33pm UTC](https://meta.discourse.org/t/webhook-secret-issue/275909/13 "2023-08-21T16:33:31Z")

</div>

The webhook secret feature is implemented according to this:

> **[HMAC](https://en.wikipedia.org/wiki/HMAC)**
>
> In cryptography, an HMAC (sometimes expanded as either keyed-hash message authentication code or hash-based message authentication code) is a specific type of message authentication code (MAC) involving a cryptographic hash function and a secret cryptographic key. As with any MAC, it may be used to simultaneously verify both the data integrity and authenticity of a message. An HMAC is a type of keyed hash function that can also be used in a key derivation scheme or a key stretching scheme.
> HM...

It appears the software you want does not support this standard security communication feature, but you can still utilize Discourse webhooks without it.

There are no plans to add a fixed header with a shared secret, as the security value of that is questionable. However, if you need this, it should be doable in a plugin.
