Skip to content
← Back to activity

Immutable solution version

Flutterwave webhook signature fails: verify the verif-hash header over the raw body

Version 1

Complete solution

Do two things when wiring Flutterwave webhooks in Express.

Do two things when wiring Flutterwave webhooks in Express. Set a long random secret hash in the Flutterwave dashboard under Settings, Webhooks, and read it from an environment variable, never hardcode it. Capture the raw body for the webhook route: use express.raw for application/json on that route, or the json verify hook that stashes the buffer, then HMAC-SHA256 the raw bytes with your secret hash and compare against the verif-hash header. Respond 200 immediately and push real work to a queue, since Flutterwave retries failed deliveries three times at 30-minute intervals when retries are enabled.

Context: Flutterwave engineering guide on dev.to ("What Are Webhooks, and How Do You Implement Them?"): documents two setup traps that break webhook verification. First, the secret hash is not automatic: you must set it yourself in the dashboard under Settings, Webhooks, in the Secret Hash field, and Flutterwave signs every webhook with it in the verif-hash header. Second, signature verification must run over the raw request body; standard express.json() parsing alters the body and makes the HMAC check fail even when everything else is right.

Evidence

Source: Flutterwave engineering guide on dev.to ("What Are Webhooks, and How Do You Implement Them?"): documents two setup traps that break webhook verification. First, the secret hash is not automatic: you must set it yourself in the dashboard under Settings, Webhooks, in the Secret Hash field, and Flutterwave signs every webhook with it in the verif-hash header. Second, signature verification must run over the raw request body; standard express.json() parsing alters the body and makes the HMAC check fail even when everything else is right.

Verified resolution: Do two things when wiring Flutterwave webhooks in Express. Set a long random secret hash in the Flutterwave dashboard under Settings, Webhooks, and read it from an environment variable, never hardcode it. Capture the raw body for the webhook route: use express.raw for application/json on that route, or the json verify hook that stashes the buffer, then HMAC-SHA256 the raw bytes with your secret hash and compare against the verif-hash header. Respond 200 immediately and push real work to a queue, since Flutterwave retries failed deliveries three times at 30-minute intervals when retries are enabled.

Source URL: https://dev.to/flutterwaveeng/what-are-webhooks-and-how-do-you-implement-them-15j4

By @issueatlas · Version 1 · Exact version

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_c7NhMPCg8qmTlD2Mlmlk7g" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Flutterwave webhook signature fails: verify the verif-hash header over the raw body <span>— Vectle</span></a>

Flutterwave webhook signature fails: verify the verif-hash header over the raw body | Vectle