Skip to content
TextArray

HMAC and hashing for API signatures: protecting webhooks

Blog /

When a third-party service sends you data via webhook or you need to authenticate an API request, you need a way to prove the message hasn't been tampered with and really came from who says it did. Hashing alone does not solve this; you need HMAC. Understanding the difference between a plain hash and an HMAC, and how to verify signatures correctly, is the difference between a secure integration and a compromised one.

What is a hash

A hash is a one-way function that turns any input—text, a file, an API response—into a fixed-length string. The same input always produces the same output. Common hashing algorithms include SHA-256, SHA-1, and MD5. You can use a hash generator to see this in action: "hello" always becomes the same SHA-256 hash. The key property is that hashing is deterministic but impossible to reverse; you cannot recover the original input from the hash.

What is HMAC

HMAC stands for Hash-based Message Authentication Code. Unlike a plain hash, HMAC combines a message with a secret key before hashing. The webhook provider has a secret key, hashes the message with that key, and sends the message and the hash to you. You repeat the process with the same secret key; if your calculated hash matches the one sent, you know the message is authentic and unmodified. The HMAC generator tool lets you test this with your own message and secret.

The critical difference: hash vs HMAC

Here's why this matters:

If a service sends you a webhook with only a hash, an attacker can intercept it, change the data, recalculate the hash, and you would not notice. With HMAC and a shared secret, the attacker cannot forge a valid signature without the key.

Verifying webhook signatures in your code

When a webhook arrives, the service provides the message payload and a signature header (often X-Signature or X-Webhook-Signature). Your code should:

  1. Retrieve your secret key from secure configuration (environment variables, a secret manager).
  2. Calculate the HMAC-SHA256 of the raw request body using that key.
  3. Compare your calculated HMAC byte-for-byte with the signature header (always use constant-time comparison to prevent timing attacks).
  4. If they match, the webhook is authentic. If not, reject it.

Most webhook providers document their HMAC algorithm and the exact format to sign—sometimes it's the raw JSON body, sometimes a timestamp concatenated with the body. Follow their spec exactly.

HMAC vs JWT: where do they fit

JWTs (JSON Web Tokens) are often confused with HMAC signatures. A JWT is a self-contained token with three parts: a header, a payload (claims), and a signature. The signature can be HMAC-based or RSA-based. JWT decoders let you inspect and verify tokens. While HMACs verify a single message, JWTs are tokens you store and send with every request or API call. For webhooks and one-off message authentication, HMAC is simpler and sufficient. For ongoing session tokens or API credentials, a JWT is often more flexible.

Privacy: sign and verify entirely in your browser

TextArray's HMAC and hash tools run entirely in your browser. No message, secret, or signature is uploaded to a server. No account is required, and the tools work offline after the page loads. You can safely paste webhook payloads and API keys to test and debug signatures without exposing data to a third party or logging service. This is especially valuable when you're working with sensitive API keys or customer data during development.

Getting started

Start by understanding hashing: use the hash generator to see how the same input always produces the same SHA-256 output. Then move to HMAC generation to see how a secret key changes the output. Try changing the key or message slightly; the HMAC flips completely, unlike a naive checksum. Once you understand the mechanics, apply it to your webhook verification logic. For sensitive payloads like encrypted text or decoded tokens, always pair them with HMAC-signed requests to guarantee integrity and origin.