Urgent.News

What's breaking now, across thousands of outlets.

Tech

GitHub webhook signature mismatch? 5 reasons X-Hub-Signature-256 won't verify (Node and Python fixes)

Disclosure: I run webhook-relay.gmitchell-relay.workers.dev , a free site with webhook error fix pages. This article was written with AI assistance and reviewed before publishing. You set up a GitHub webhook, add a secret, write ten lines of HMAC code, and every delivery comes back 401 signature mismatch . The code usually looks right. Something about the inputs is wrong. Here's how GitHub signs…

GitHub sends a signature as part of every webhook delivery, which is expected to be verified by the receiving application. However, there are five common reasons why the signature verification might fail, even when the code seems to be correct. Here are those reasons, along with the corresponding fixes.

Firstly, if no secret is configured for the webhook in the GitHub settings, there will be no signature header sent. In this case, the application's code will attempt to compare against an undefined or empty string, leading to a verification mismatch. To resolve this, a secret must be set on the webhook, and the handler should explicitly reject requests with a missing header by returning a 401 status code.

Secondly, a common mistake is using the wrong signature algorithm. GitHub uses the SHA-256 signature, but some developers might be comparing against a SHA-1 signature, or vice versa. Additionally, remember that the value starts with "sha256=", so it is essential to compare against "sha256=" + hexDigest, or strip the prefix first before comparing.

Thirdly, the most common cause for verification failure is hashing the parsed JSON body instead of the raw body. Some frameworks, such as Express in Node.js, automatically parse the request body into an object, and hashing the parsed object will not reproduce GitHub's exact bytes. To fix this, hash the raw bytes of the request body. In Express, this can be done by using express.raw() on the webhook route only. In Flask, use request.get_data().

Fourthly, if the webhook's content type is form-encoded (application/x-www-form-urlencoded), GitHub signs the entire form body, not the decoded JSON inside it. If the handler extracts the payload and hashes it, the verification will fail. To resolve this issue, switch the webhook's content type to application/json, or hash the raw form body exactly as received.

Lastly, the secret used for verification might not be the one intended. Common variations include a trailing newline or space in the environment variable, different secrets for different webhooks, or using a different secret for a GitHub App's webhook compared to a repository webhook. To avoid this issue, set a fresh secret on the webhook and in the environment variable, then redeploy the application.

Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.

Read the original at dev.to →

More in Tech

Dark Sky Walk

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass What I Built Dark Sky Walk : an offline night-sky companion that gets people out of the house after sunset.

  • Dark Sky Walk app encourages outdoor stargazing after sunset.
  • Uses local language model and open astronomy data for offline functionality.
  • Provides accurate celestial targets checklist with red-light, low-brightness cards.

Atlassian Team '26 Europe recap and highlights

Atlassian Team '26 Europe ran at RAI Amsterdam from 6 to 8 October, with Partner Accelerate on the Monday before, and this is our recap. Atlassian announced a lot.

  • Atlassian Team 26 Europe held in Amsterdam from Oct 6-8
  • 23 Service Collection items marked Generally Available
  • Founder Keynote ended early due to power outage

More from Friday 9 October →