Course contentsShow
← Node.js
Lesson 986 of 1,9809. Authentication and Identity ManagementFree lesson

Securing Webhooks from Identity Providers

Verify the authenticity of signed webhooks received from external authorization services.

In this lesson, you will learn how to verify that incoming webhook requests were genuinely sent by your Identity Provider (IdP) and have not been tampered with in transit.

Why Webhooks Need Verification

When an Identity Provider notifies your application of an event—like a user profile update or a credential change—it sends an HTTP POST request to your webhook endpoint. Since this endpoint must be publicly accessible, anyone could send a fake request to trigger unauthorized actions in your system. To prevent this, IdPs "sign" their payloads using a secret key, and it is your job to re-calculate that signature to confirm authenticity.

The Verification Workflow

The process follows a standard cryptographic pattern:

  1. The IdP computes a Hash-based Message Authentication Code (HMAC) of the raw request body using a shared secret.
  2. The IdP sends this signature in an HTTP header (e.g., X-Hub-Signature-256).
  3. Your server intercepts the request, retrieves the raw body, and computes its own HMAC using the same secret.
  4. You compare your computed signature with the one provided in the header. If they match, the request is valid.

Implementation Example

Using Node's crypto module, you can verify the signature before processing the data:

const crypto = require('crypto');

function verifyWebhook(req, secret) {
  const signature = req.headers['x-hub-signature-256'];
  const hmac = crypto.createHmac('sha256', secret);
  const digest = hmac.update(JSON.stringify(req.body)).digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
}

Crucial Note: Always use crypto.timingSafeEqual when comparing signatures. Standard string comparison (===) returns early if characters don't match, which creates a side-channel vulnerability where an attacker can guess the signature character-by-character based on how long your server takes to respond. By using a constant-time comparison, you ensure the processing time is identical regardless of whether the signature is correct or incorrect, effectively neutralizing this risk.

Key Takeaway: Never trust the data in a webhook without first verifying its integrity using a shared secret and a constant-time cryptographic comparison.