Skip to content

Instantly share code, notes, and snippets.

@emerleite
Created October 28, 2024 14:14
Show Gist options
  • Save emerleite/beebcd91c8a42c20371979d656c9ed12 to your computer and use it in GitHub Desktop.
Save emerleite/beebcd91c8a42c20371979d656c9ed12 to your computer and use it in GitHub Desktop.
Hono middleware - Meta WhatsApp Business API Message Validate
import { createMiddleware } from 'hono/factory'
export function metaValidateWebhookSignature() {
return createMiddleware(async (c, next) => {
const requestBody = await c.req.arrayBuffer()
const payloadSignature = c.req.header('X-Hub-Signature-256')
const validRequest = await verifySignature(c.env.META_API_SECRET, requestBody, payloadSignature)
console.log('Meta Valid Request?', validRequest)
if (!validRequest) { return c.json({ error: 'Invalid signature' }, 403) }
await next()
})
}
/*
Meta Docs
https://developers.facebook.com/docs/messenger-platform/webhooks/
https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/components
https://developers.facebook.com/docs/graph-api/webhooks/getting-started#create-endpoint
https://developers.facebook.com/docs/whatsapp/cloud-api/guides/set-up-webhooks
https://developers.facebook.com/docs/whatsapp/cloud-api/webhooks/payload-examples/
Research
https://developers.facebook.com/docs/whatsapp/sample-app-endpoints
https://stackoverflow.com/questions/72813196/how-to-register-whatsapp-webhooks-in-nodejs
https://glitch.com/edit/#!/whatsapp-cloud-api-echo-bot
https://www.linkedin.com/pulse/facebook-webhook-payload-signature-verification-aspnet-rehman-tw8xf/
*/
async function verifySignature(secret, payload, signatureHeader) {
if (!signatureHeader || signatureHeader.length == 0) {
return false;
}
const signature = signatureHeader.split('sha256=')[1]
if (!signature || signature.length == 0) {
return false;
}
// Encode the secret and the order
const encoder = new TextEncoder();
const encodedSecret = encoder.encode(secret);
const encodedPayload = new Uint8Array(payload).buffer;
// Import the secret key
const key = await crypto.subtle.importKey(
'raw',
encodedSecret,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
// Create the HMAC signature
const signatureArrayBuffer = await crypto.subtle.sign(
'HMAC',
key,
encodedPayload
);
// Convert the ArrayBuffer to a hexadecimal string
const calculatedSignature = Array.from(new Uint8Array(signatureArrayBuffer))
.map(byte => byte.toString(16).padStart(2, '0'))
.join('');
return signature === calculatedSignature;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment