Verifying Github webhooks requests with Node.js
- Published on
- • 3 mins read•21 views
Webhooks provide a way for apps to receive real-time information from Github whenever there is a new event. It is important to ensure that the webhook request is coming from Github and process it accordingly.
This is how you can simply verify the webhook signature in a Remix app (or any Node.js server).
import type { ActionFunction } from "@remix-run/node";
import { json } from "@remix-run/node";
import crypto from "crypto";
// The `loader` function handle the GET request to the route
// In this case, we are returning a 400 status, cause we only want to handle POST requests only
// See more about Remix route's loader here: https://remix.run/docs/en/route/loader
export let loader = () => {
return json({ message: "Bad request!" }, { status: 400 });
};
// The `action` function handle non-GET requests to the route
// See more about Remix route's action here: https://remix.run/docs/en/route/action
export let action: ActionFunction = async ({ request }) => {
// Return a 405 status if the request method is not POST
if (request.method !== "POST") {
return json({ message: "Method not allowed" }, 405);
}
// Verify the webhook signature
let signature = request.headers.get("X-Hub-Signature-256");
let rawBody = await request.text();
let webhookSecret = process.env.GITHUB_APP_WEBHOOK_SECRET;
let hmac = crypto.createHmac("sha256", webhookSecret);
hmac.update(rawBody);
let generatedSignature = `sha256=${hmac.digest("hex")}`;
if (signature !== generatedSignature) {
return json({ message: "Webhook must originate from GitHub!" }, 400);
}
let event = request.headers.get("X-GitHub-Event");
console.log(`✅ Github webhook verified!. Event: "${event}"`);
try {
let payload = JSON.parse(rawBody);
if (event === "your_subscribed_event") {
let { action, sender, ...rest } = payload;
// Do something with the payload from Github
// `action` is the action that triggered the event
// `sender` is the user that triggered the event
}
return json({ message: "Webhook processed successfully!", event }, 200);
} catch (err) {
console.log(`❌ Error processing webhook: ${err?.toString()}`);
// Return a 200 status to Github to avoid retries
// even if the webhook payload is not processed successfully in your app
return json({ message: "Webhook processed!", event }, 200);
}
};
Feel free to use this snippet in your app if you find it useful!
Happy verifying!