Test a GitHub webhook locally
To validate a GitHub webhook handler, there's no need to push commits or open real PRs. Generate a GitHub event signed with HMAC-SHA256, edit the payload (repo, branch, author) and send it to your local server. Your X-Hub-Signature-256 verification is tested right away.
Verify the signature server-side
import crypto from 'crypto';
const sig = req.headers['x-hub-signature-256'];
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(rawBody)
.digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));To receive a real GitHub webhook on your machine without deploying, set the URL of your Relay tunnel in the repo settings.
Already receiving real deliveries and one is being rejected? Paste the raw body, secret and header into the GitHub signature validator to see exactly why X-Hub-Signature-256 doesn't match.
Frequently asked questions
How do I simulate a GitHub push on my local server?
Pick the push event above, paste the webhook secret configured in your repo, enter your handler's URL (via Relay), then send. The X-Hub-Signature-256 header is computed with HMAC-SHA256 just like GitHub does.
What's the difference between X-Hub-Signature and X-Hub-Signature-256?
X-Hub-Signature uses SHA-1 (legacy), X-Hub-Signature-256 uses SHA-256 (recommended). The generator produces both headers to cover every case.
How do I verify the signature server-side?
Compute HMAC-SHA256(rawBody, secret) and compare it in constant time with the header value (after 'sha256='). See the code example below.
Can I test pull_request and issues too?
Yes, the push, pull_request and issues events are available, each with the correct X-GitHub-Event header.