Webhook Signature Verification: How to Secure Your Integrations

Learn what webhook signature verification is, why it’s critical for security, and how to implement it correctly. This step-by-step guide covers HMAC, SHA-256, and real-world examples using Apidog — the free API testing and webhook tool trusted by developers worldwide.

Ashley Innocent

Ashley Innocent

22 December 2025

Webhook Signature Verification: How to Secure Your Integrations

Webhooks are one of the most powerful ways to receive real-time updates from third-party services. A single HTTP POST from Stripe, GitHub, Shopify, or Twilio can trigger critical business logic in your application — charging a customer, updating a repository, shipping an order, or sending a confirmation SMS.

But every webhook request arrives over the public internet. And that means anyone who guesses or discovers your webhook URL can send malicious payloads that look completely legitimate. Without proper authentication, your application has no way to tell the difference between a real event and a forged one.

That’s where webhook signature verification comes in. It’s a simple, standardized mechanism that ensures every incoming webhook request is genuinely from the service you expect and hasn’t been altered in transit.

In this comprehensive guide, you’ll learn exactly how webhook signature verification works,  and how to implement it correctly in popular languages. You’ll also see common mistakes to avoid and how to test everything end-to-end — quickly and reliably.

💡
Before we get into the technical details, I want to make sure you have the right tool to verify and debug webhooks in minutes. Apidog is completely free to download and offers built-in webhook signature verification testing, mock servers, and real-time payload inspection — no credit card required. It’s the fastest way to confirm that your verification logic actually works.
button

What Is Webhook Signature Verification?

Webhook signature verification is the process of confirming that an incoming webhook request actually comes from the service you expect and hasn’t been tampered with.

Most providers use HMAC (Hash-based Message Authentication Code) with SHA-256 or SHA-512. The service computes:

signature = HMAC-SHA256(secret_key, payload)

Then they send the signature in a header (usually X-Signature, Signature, or X-Hub-Signature-256).

Your server:

  1. Receives the payload as raw bytes (important!)
  2. Recomputes the HMAC using your stored secret
  3. Compares the computed signature with the received one

If they match exactly, you process the webhook. Otherwise, you return HTTP 401 or 403.

What is Webhooks API? A Guide to Instant Communication Between Apps
What are Webhooks? Learn how this “reverse API” works for real-time notifications, why it’s essential for real-time communication between apps.

Why HMAC-SHA256 Is the Industry Standard

Providers choose HMAC-SHA256 for good reasons:

GitHub, Stripe, Shopify, Slack, and dozens of others all use HMAC-SHA256.

How to Implement Webhook Signature Verification in Node.js

Let’s start with a real-world example in Node.js.

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const hmac = crypto.createHmac('sha256', secret);
  const computedSignature = hmac.update(payload).digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(computedSignature),
    Buffer.from(signature)
  );
}

Key points to notice:

Express middleware example:

app.post('/webhooks/stripe', (req, res, next) => {
  const signature = req.headers['stripe-signature'];
  const secret = process.env.STRIPE_WEBHOOK_SECRET;

  // Get raw body (Express needs middleware to preserve raw body)
  const rawBody = req.rawBody || req.body; // use body-parser with verify option

  if (!verifyWebhookSignature(rawBody, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // Signature is valid → process the event
  next();
});

Python Implementation (FastAPI + Pydantic)

from fastapi import FastAPI, Request, HTTPException
import hmac
import hashlib

app = FastAPI()

def verify_signature(payload: bytes, signature: str, secret: str) -> bool:
    computed = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(computed, signature)

@app.post("/webhooks/github")
async def github_webhook(request: Request):
    signature = request.headers.get("X-Hub-Signature-256")
    if not signature:
        raise HTTPException(status_code=401, detail="Missing signature")

    payload = await request.body()

    if not verify_signature(payload, signature.split('=')[1], SECRET):
        raise HTTPException(status_code=401, detail="Invalid signature")

    # Process webhook
    return {"status": "ok"}

Common Pitfalls Developers Make (and How to Avoid Them)

1. Using JSON.stringify() or Parsed Body

Many frameworks parse JSON automatically. This breaks verification because whitespace, key order, and formatting differ.

Solution: Always capture the raw body before parsing.

In Express: Use body-parser with { verify: true }

In FastAPI: Use await request.body()

2. Comparing Strings with ===

Timing attacks can leak information. Use crypto.timingSafeEqual or hmac.compare_digest.

3. Storing Secrets in Code

Use environment variables or secret managers (AWS Secrets Manager, HashiCorp Vault, etc.).

4. Forgetting to Handle Replay Attacks

Most providers include a timestamp. Check that the event is recent (e.g., within 5 minutes).

const timestamp = req.headers['X-Signature-Timestamp'];
if (Date.now() - timestamp > 5 * 60 * 1000) {
  return res.status(401).send('Timestamp too old');
}

5. Using SHA-1 (Still Happens!)

GitHub deprecated SHA-1 in 2022. Always use SHA-256.

Testing Webhook Signature Verification with Apidog

Manually testing webhooks is painful. You send a request, check logs, fix, repeat.

Apidog makes this trivial:

In your Apidog project, click the + icon in the left sidebar and choose "New Other Protocol APls" > "Webhook".

CleanShot 2025-11-05 at 17.18.02@2x.png

After creating the Webhook, fill out the following fields in the editor:Request Method: TypicallyPOST.Webhook name: This will appear in the API documentation and OpenAPI export, e.g., order.Debug URL(optional): The actual URL used for sending test requests. Note: This is for testing purposes only and will not be included in documentation.Other Info: Such as the request body.

image.png

ClickSaveonce you've completed all required fields.
Just enter your Webhook URL into the Debug URL field, then click Send to simulate a Webhook call.

image.png

I’ve saved hours of debugging with Apidog’s webhook simulator. It even supports Stripe’s exact stripe-signature format and GitHub’s sha256=... prefix.

Real-World Example: Verifying Stripe Webhooks

Stripe uses a special header format:

stripe-signature: t=1681234567,v1=abc123...,v0=def456...

You must:

Stripe provides official libraries to handle this complexity:

const stripe = require('stripe')('sk_...');
stripe.webhooks.constructEvent(payload, sigHeader, endpointSecret);

But understanding the underlying HMAC is crucial when you need to implement it yourself.

Advanced Topics: Tolerating Multiple Signatures

Some providers (like Stripe) send multiple signatures for backward compatibility. Your code should:

Security Best Practices in 2025

Conclusion: Small Verification Step, Big Security Gain

Webhook signature verification sounds like a tiny detail. But it’s the difference between a secure application and one that attackers can trivially exploit.

Implement it correctly, test it thoroughly with tools like Apidog, and sleep better knowing your integrations are protected.

Download Apidog for free today and verify your first webhook in under 5 minutes. It’s the fastest way to prove your code actually works.

button

Explore more

What is User Acceptance Testing (UAT) and How to Perform It?

What is User Acceptance Testing (UAT) and How to Perform It?

Complete guide to UAT (User Acceptance Testing) covering definition, timing, step-by-step execution, and how Apidog streamlines API validation during business acceptance testing.

19 December 2025

How to Implement Effective Fintech API Retry Logic: Best Practices and Strategies

How to Implement Effective Fintech API Retry Logic: Best Practices and Strategies

Discover how to build robust fintech API retry logic to handle transient failures, rate limits, and network issues. Learn exponential backoff, idempotency, circuit breakers, and testing strategies with tools like Apidog for resilient financial integrations.

19 December 2025

Your API Docs Look Done—But Are They Really? Let AI Check

Your API Docs Look Done—But Are They Really? Let AI Check

Apidog’s AI features help you turn existing API docs into clear, standardized, and complete documentation. From importing non-standard formats to refining field names, generating mock data, and running completeness and compliance checks, AI guides you step by step toward better API docs.

18 December 2025

Practice API Design-first in Apidog

Discover an easier way to build and use APIs