DEV Community

EventDock
EventDock

Posted on • Originally published at eventdock.app

Fix "Required headers missing: x-hub-signature-256" in @octokit/webhooks

This guide also lives on eventdock.app.

Your GitHub webhook handler responds 400 with:

{"error": "Required headers missing: x-hub-signature-256"}
Enter fullscreen mode Exit fullscreen mode

(older @octokit/webhooks versions: x-hub-signature)

The middleware checks three headers on every delivery — x-github-event, x-hub-signature-256, x-github-delivery — and rejects the request if any is absent. Here are the causes, ordered by how often they're the culprit.

1. No webhook secret configured (the usual one)

GitHub only signs deliveries when the webhook has a secret. No secret → GitHub omits X-Hub-Signature and X-Hub-Signature-256 entirely → octokit reports them missing.

Fix:

  1. Repo (or org) → Settings → Webhooks → your hook → Secret: set a strong random value.
  2. Pass the same value to your handler:
import { Webhooks, createNodeMiddleware } from "@octokit/webhooks";

const webhooks = new Webhooks({
  secret: process.env.GITHUB_WEBHOOK_SECRET, // must match the webhook's Secret field
});
Enter fullscreen mode Exit fullscreen mode

After setting the secret, use Redeliver on a recent delivery (webhook settings → Recent Deliveries) and confirm the request headers now include X-Hub-Signature-256.

2. The request isn't from GitHub

Health checks, uptime probes, security scanners, and your own curl tests hit the same route without GitHub's headers and trip the 400. Real GitHub deliveries have a User-Agent starting with GitHub-Hookshot/ and a unique X-GitHub-Delivery id. To test locally, copy a payload from Recent Deliveries including all four headers, or just use Redeliver.

3. A proxy or framework strips the headers

Some reverse proxies, API gateways, and serverless adapters drop or rename non-standard X- headers. Diagnose by logging exactly what arrives:

app.use("/api/webhooks", (req, _res, next) => {
  console.log(JSON.stringify(req.headers, null, 2)); // is x-hub-signature-256 present at all?
  next();
});
Enter fullscreen mode Exit fullscreen mode

If the header reaches your edge but not your handler, the thing in between (nginx underscores_in_headers rules, an API gateway header allowlist, a Lambda adapter) is eating it.

4. Old @octokit/webhooks expecting the legacy header

Very old versions (v5-era) validated the SHA-1 x-hub-signature header; current versions require the SHA-256 variant. GitHub sends both when a secret is set, so the practical fix is the same: set the secret, then upgrade @octokit/webhooks.

5. Wrong route wired to the middleware

If createNodeMiddleware(webhooks, { path: "/api/webhooks" }) is mounted on a path that also serves other traffic (or a catch-all), every non-webhook request to it produces this 400 in your logs. Give the webhook endpoint its own dedicated path.


Debugging webhook headers blind? EventDock sits in front of your handler, captures every GitHub delivery with its full original headers, verifies signatures, and retries when your server is down. Free tier: 5,000 events/mo, no card.

Top comments (0)