DEV Community

Spubhi
Spubhi

Posted on

Why HMAC Is the Right Choice for Webhook Security (and Why Spubhi Makes It Simple)

Webhooks are one of the most common integration patterns today. They’re also one of the easiest places to make security mistakes.

In this post, I’ll focus on why HMAC is a better approach for securing webhooks and how Spubhi keeps the implementation simple and predictable.

This is not a comparison-heavy or theory-heavy article — it’s about practical implementation and reliability.

The Core Problem with Webhook Security

A webhook endpoint is publicly accessible by design.
That means anyone can send a request to it unless you validate the sender.

The real challenge is not adding authentication, but ensuring that:

The request was not modified

The sender actually knows a shared secret

The validation works reliably across different clients and platforms

This is where many webhook implementations break down.

Why HMAC Works Well for Webhooks

HMAC (Hash-based Message Authentication Code) solves a very specific problem:
verifying both authenticity and integrity of a request.

When using HMAC:

The sender signs the raw request body using a shared secret

The receiver independently generates the same signature

If the signatures match, the request is trusted

No secrets are sent over the wire.
Only a signature is transmitted.

This has a few important implications:

1. No secret exposure

Unlike tokens or passwords, the shared secret is never transmitted in the request.

2. Payload integrity is guaranteed

If even one character in the request body changes, the signature validation fails.

3. Stateless validation

The server does not need to store sessions or tokens per request.
It only needs the shared secret and the incoming payload.

4. Language-agnostic

HMAC works the same way in Java, Node.js, Python, Go, or any other language.

This makes it ideal for webhook-based systems.

Common HMAC Implementation Pitfalls

Most HMAC failures don’t come from cryptography — they come from inconsistencies.

Some common issues:

Signing parsed JSON instead of the raw body

Different JSON serialization on sender and receiver

Header mismatches or late header injection

Async signing issues in tools like Postman

A reliable HMAC implementation must:

Use the exact raw request body

Normalize the payload consistently

Use a predictable header for the signature

Validate before any business logic executes

Why Spubhi Keeps HMAC Simple

Spubhi was designed with webhook security as a first-class concern.

Here’s what Spubhi does differently:

1. Raw body handling is explicit

Spubhi validates HMAC against the actual incoming payload, not a re-serialized version.

This avoids subtle mismatches that break signature verification.

2. Header-based authentication only

Spubhi expects the HMAC signature in a single, clear header:

X-SPUBHI-SECRET

No ambiguity. No hidden behavior.

3. No encoding or decoding of secrets

Secrets are treated as-is.
There’s no unnecessary base64 wrapping or transformation.

What you sign on the client is exactly what Spubhi verifies on the server.

4. Authentication happens before flow execution

If authentication fails, the request is rejected immediately.
No partial execution, no side effects.

This makes webhook behavior predictable and safe.

Minimal Client-Side HMAC Example

// Normalize JSON exactly like your current logic
const body = JSON.stringify(JSON.parse(pm.request.body.raw));

// HMAC secret
const secret = "hmac_Qv33h2Yp7SpLwl7mQ8geU7R8SrfRZ27BpX5j0tHM";

// Encode inputs
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const bodyData = encoder.encode(body);

// Generate HMAC-SHA-256
crypto.subtle.importKey(
  "raw",
  keyData,
  { name: "HMAC", hash: "SHA-512" },
  false,
  ["sign"]
).then(key => {
  return crypto.subtle.sign("HMAC", key, bodyData);
}).then(signature => {
  const hmac = Array.from(new Uint8Array(signature))
    .map(b => b.toString(16).padStart(2, "0"))
    .join("");

  // SAME header name you already use
  pm.request.headers.upsert({
    key: "X-SPUBHI-SECRET",
    value: hmac
  });
});
Enter fullscreen mode Exit fullscreen mode

That’s it.

No SDKs.
No custom formats.
No hidden transformations.
**
Minimal Server-Side Validation Logic**

On the server:

  1. Read the raw request body
  2. Generate HMAC using the same secret
  3. Compare it with the incoming header
  4. Reject if it doesn’t match

Simple logic — easy to audit, easy to debug.

Final Thoughts

Webhook security doesn’t need to be complex — it needs to be correct and consistent.

HMAC works well because it:

Protects payload integrity

Avoids secret exposure

Scales without state

Works across platforms

Spubhi keeps this model simple by:

Avoiding magic

Enforcing clear boundaries

Treating authentication as a first step, not an afterthought

If you’re building webhook-driven integrations, HMAC done right is enough — and simplicity is what makes it reliable.

webhooks

apissecurity

hmac

backend

integration

Top comments (0)