Why You Shouldn't Use an Online Webhook Secret Generator

Online secret generators ask you to trust someone else's server with a value whose whole point is secrecy. Use your terminal, or your own browser console, instead.

Search for "webhook secret generator" and you get a page of websites offering to generate one for you in the browser. Convenient, but a secret's entire value comes from nobody else ever seeing it, and a generator website is somebody else's computer. This post explains the actual risks, then gives you generators you already own: your terminal and, surprisingly, your browser's own developer console. Every command was executed and verified before publishing.

The problem with online generators

You cannot verify where the value came from. A good generator site uses crypto.getRandomValues() client-side. A bad one generates server-side and sends the secret over the wire, calls Math.random() (predictable, not cryptographic), or is a thin page wrapping an API you never see. From the outside, all of them look identical. You would have to read and trust the minified JavaScript on every visit, because the page can change tomorrow.

The value can leak in transit and at rest. Anything rendered by a server can end up in that server's access logs, an analytics payload, a CDN cache, or the third-party scripts loaded next to the generator. Browser extensions can read the page too. None of this is paranoid; it is just how the web works, and it is all avoided by never letting the secret exist outside your machine.

It builds the wrong habit. Webhook secrets are low-stakes compared to, say, private keys, and an attacker exploiting a leaked webhook secret still has work to do. But the person who pastes a webhook secret from a website today pastes a database password into one tomorrow. The correct habit costs one line in a terminal.

Your terminal is the generator

Every operating system ships a cryptographically secure random source and a way to read it. These produce a 64-character hex secret with 256 bits of entropy:

Linux and macOS:

openssl rand -hex 32

Windows (PowerShell, built into Windows 10/11):

$rng=[System.Security.Cryptography.RandomNumberGenerator]::Create(); $b=New-Object byte[] 32; $rng.GetBytes($b); ($b | ForEach-Object ToString x2) -join ''

Any OS with Python 3:

python3 -c "import secrets; print(secrets.token_hex(32))"

More variants, including a pure-shell one-liner for minimal containers, are in our full guide to generating a webhook secret on Linux, macOS, and Windows.

The honest middle ground: your browser console

If you like generating secrets in a browser, you do not need a website for it. Every modern browser exposes the same CSPRNG that good generator sites use, and you can call it yourself with no page involved. Press F12 (or Cmd+Option+J on a Mac), and paste this into the Console tab:

crypto.getRandomValues(new Uint8Array(32)).reduce((s,b)=>s+b.toString(16).padStart(2,'0'),'')

It prints a 64-character hex secret, generated entirely on your machine by the browser's cryptographic random source. This is everything an online generator claims to do, minus the server, the network, and the trust question. Run it on about:blank if you want certainty that no page scripts are watching.

What to do with the secret

A webhook secret only works when both sides hold it. On the receiving side, Core Webhook Module (open source, self-hosted) takes the secret from an environment variable, so it never appears in a config file. In webhooks.json:

{
    "orders": {
        "data_type": "json",
        "module": "log",
        "authorization": "Bearer {$WEBHOOK_SECRET}"
    }
}

Start the receiver with the secret you just generated:

docker run --rm -d --name webhook -p 8099:8000 \
  -v "$PWD/webhooks.json:/app/webhooks.json:ro" \
  -v "$PWD/connections.json:/app/connections.json:ro" \
  -e WEBHOOK_SECRET=your-generated-secret \
  spiderhash/webhook:latest

We verified the enforcement before publishing: a request with the correct Authorization: Bearer value returns HTTP 200 with {"message":"200 OK"}, a wrong value returns HTTP 401 with {"detail":"Unauthorized"}, and comparison happens in constant time to resist timing attacks. Give the same value to the sending side (GitHub's secret field, Telegram's secret_token parameter, your own service's config) and the loop is closed.

For how long the secret should be, where to store it, and how to rotate it without dropping deliveries, continue with webhook secret best practices.


Keep reading

Browse more: all integration guides · webhook security · HTTPS setup · documentation · what is Core Webhook Module?

Subscribe to Free Webhook Tool

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe