Verify GitHub Webhook Signatures
GitHub signs webhook deliveries with HMAC-SHA256 over the raw request body and sends the result in the X-Hub-Signature-256 header (formatted sha256=…). Paste the raw body, the secret you configured on the webhook, and the header value.
Everything runs in your browser — the payload and secret never leave this page. Want to verify a different provider? See the webhook signature verifier hub or the generic HMAC generator.
How GitHub signs webhooks
- Take the raw request body exactly as delivered.
- Compute HMAC-SHA256 using your webhook secret as the key, hex-encoded.
- Prefix it with
sha256=and compare toX-Hub-Signature-256with a constant-time check.
Reference: GitHub signature documentation.
Verify GitHub signatures in code
const crypto = require('crypto');
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(rawBody) // raw bytes of the request body
.digest('hex');
const received = req.headers['x-hub-signature-256'];
const valid = crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(received));import hmac, hashlib
expected = 'sha256=' + hmac.new(
secret.encode(), raw_body, hashlib.sha256).hexdigest()
received = request.headers['X-Hub-Signature-256']
valid = hmac.compare_digest(expected, received)Frequently asked questions
X-Hub-Signature vs X-Hub-Signature-256?
GitHub sends both. X-Hub-Signature is the legacy SHA-1 version; always verify X-Hub-Signature-256 (SHA-256) instead.
Where do I set the secret?
In the repository or organization webhook settings, in the "Secret" field. GitHub then signs every delivery with it; an empty secret means no signature is sent.
Verify other providers
Receiving GitHub webhooks on a server behind a firewall or on localhost? Webhook Relay can forward them to your internal service and even verify or transform them before delivery.
