Verify Github webhooks
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/loaderexport 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/actionexport 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 event: ${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!
react to this snippet