search
Tutorials

Fix: Error: Failed to verify webhook signature error

Quick fix for 'Failed to verify webhook signature' error. Learn how to properly implement webhook signature verification in your applications.

person By Gautam Sharma
calendar_today January 8, 2026
schedule 3 min read
Webhooks Security Signature Verification API Error Fix

The ‘Failed to verify webhook signature’ error occurs when the signature sent with a webhook request doesn’t match the expected signature calculated using your secret key.


How the Error Happens

❌ Error Scenario:

// ❌ This causes signature verification to fail
// Webhook receives payload but signature doesn't match
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature']; // ❌ Wrong header name
  const expected = calculateSignature(req.body, 'wrong-secret');
  if (signature !== expected) {
    throw new Error('Failed to verify webhook signature'); // ❌ Error thrown
  }
});

✅ Quick Fix - Proper Signature Verification

Solution 1: Stripe Webhook Verification

// ✅ Stripe webhook verification
const stripe = require('stripe')('sk_test_...');

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  const sig = req.headers['stripe-signature'];
  const endpointSecret = 'whsec_...'; // ✅ Your webhook signing secret

  let event;

  try {
    // ✅ Verify signature
    event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
  } catch (err) {
    console.log(`Webhook signature verification failed. ${err.message}`);
    return res.status(400).send(`Webhook Error: ${err.message}`);
  }

  // ✅ Process webhook event
  console.log('Received event:', event.type);
  res.json({received: true});
});

Solution 2: Generic Signature Verification

// ✅ Generic webhook signature verification
const crypto = require('crypto');

function verifySignature(payload, signature, secret) {
  // ✅ Create expected signature
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');
  
  // ✅ Compare signatures securely
  return crypto.timingSafeEqual(
    Buffer.from(`sha256=${expectedSignature}`, 'utf8'),
    Buffer.from(signature, 'utf8')
  );
}

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-hub-signature-256']; // ✅ Correct header
  const secret = process.env.WEBHOOK_SECRET;
  
  if (!verifySignature(req.body, signature, secret)) {
    return res.status(401).send('Unauthorized: Invalid signature');
  }
  
  // ✅ Process webhook
  res.status(200).send('OK');
});

Solution 3: GitHub Webhook Verification

// ✅ GitHub webhook verification
const crypto = require('crypto');

app.post('/github-webhook', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-hub-signature-256'];
  const payload = req.body;
  const secret = process.env.GITHUB_WEBHOOK_SECRET;
  
  // ✅ Calculate expected signature
  const expectedSignature = `sha256=${crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex')}`;
  
  // ✅ Verify signature
  if (signature !== expectedSignature) {
    return res.status(401).send('Unauthorized');
  }
  
  // ✅ Process GitHub event
  const event = JSON.parse(payload.toString());
  console.log(`Received ${event.action} event for ${event.repository.name}`);
  
  res.status(200).send('OK');
});

Solution 4: PayPal Webhook Verification

// ✅ PayPal webhook verification
app.post('/paypal-webhook', express.json(), async (req, res) => {
  try {
    const webhookId = process.env.PAYPAL_WEBHOOK_ID;
    const verifyUrl = 'https://api.paypal.com/v1/notifications/verify-webhook-signature';
    
    const verificationBody = {
      auth_algo: req.headers['paypal-auth-algo'],
      cert_url: req.headers['paypal-cert-url'],
      transmission_id: req.headers['paypal-transmission-id'],
      transmission_sig: req.headers['paypal-transmission-sig'],
      transmission_time: req.headers['paypal-transmission-time'],
      webhook_id: webhookId,
      webhook_event: req.body
    };
    
    // ✅ Verify with PayPal
    const response = await fetch(verifyUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${accessToken}`
      },
      body: JSON.stringify(verificationBody)
    });
    
    const result = await response.json();
    if (result.verification_status !== 'SUCCESS') {
      return res.status(401).send('Invalid signature');
    }
    
    // ✅ Process webhook
    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook verification error:', error);
    res.status(500).send('Error processing webhook');
  }
});
Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

Tutorials

Fix: invalid_client OAuth error

Complete guide to fix 'invalid_client' OAuth error. Learn how to resolve client credentials and configuration issues in OAuth implementations.

January 8, 2026
Tutorials

Fix: Stripe webhook not triggering error

Quick fix for 'Stripe webhook not triggering' error. Learn how to properly configure and debug Stripe webhook endpoints.

January 8, 2026
Tutorials

How to Fix: 403 Forbidden Error - Complete Tutorial

Complete guide to fix 403 Forbidden errors. Learn how to resolve permission issues with practical solutions, authorization management, and best practices for secure API communication.

January 8, 2026