knowledgesdk.com/glossary/hmac
Infrastructure & DevOpsintermediate

Also known as: Hash-based Message Authentication Code, webhook signature

HMAC

Hash-based Message Authentication Code — a cryptographic signature used to verify that webhook payloads are authentic and untampered.

What Is HMAC?

HMAC stands for Hash-based Message Authentication Code. It is a cryptographic algorithm that combines a secret key with a message to produce a fixed-length signature. The receiver can recompute the same signature using the same key and message — if the signatures match, the message is authentic and has not been modified in transit.

In the context of webhooks, HMAC solves a fundamental trust problem: how do you know an HTTP request to your endpoint actually came from the service you trust, and not from a malicious third party?

How HMAC Signing Works

The signing process follows these steps:

  1. The sender (e.g., KnowledgeSDK) concatenates the raw request body with a timestamp.
  2. It computes HMAC-SHA256(secret_key, message) to produce a hex digest.
  3. It includes the digest in a request header: X-KnowledgeSDK-Signature: sha256=<hex>.
  4. Your server recomputes the same HMAC using the shared secret and compares the result.
signature = HMAC-SHA256(webhook_secret, raw_body + timestamp)

The timestamp is included to prevent replay attacks — an attacker capturing a valid request and re-sending it later.

Verifying a KnowledgeSDK Webhook in Node.js

import crypto from "crypto";

export function verifyWebhookSignature(
  rawBody: string,
  signature: string,
  secret: string,
  timestamp: string
): boolean {
  const message = `${timestamp}.${rawBody}`;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(message)
    .digest("hex");

  // Use timingSafeEqual to prevent timing attacks
  const sigBuffer = Buffer.from(signature.replace("sha256=", ""), "hex");
  const expectedBuffer = Buffer.from(expected, "hex");

  if (sigBuffer.length !== expectedBuffer.length) return false;
  return crypto.timingSafeEqual(sigBuffer, expectedBuffer);
}

Key points in this implementation:

  • Use crypto.timingSafeEqual instead of ===. String comparison short-circuits on the first differing character, leaking information about how close an attacker's guess is.
  • Reject stale timestamps. Refuse requests where the timestamp is more than 5 minutes old.
  • Read the raw body. Parsing JSON before hashing will produce a different byte sequence. Always hash the raw request body string.

Why Not Just Check the API Key?

Your API key (knowledgesdk_live_*) authenticates outbound requests you make to KnowledgeSDK. Webhooks flow in the opposite direction — KnowledgeSDK calls you. Your endpoint is public, so anyone could POST to it. HMAC signing is the mechanism that proves inbound webhook requests are genuine.

Common Mistakes

  • Parsing the body with a JSON middleware before hashing it (alters whitespace).
  • Comparing signatures with === instead of a constant-time function.
  • Forgetting to validate the timestamp, leaving the endpoint vulnerable to replay attacks.
  • Storing the webhook secret in source control instead of environment variables.

Further Reading

Related Terms

Infrastructure & DevOpsbeginner
Webhook
An HTTP callback that sends real-time event notifications from a server to a client-specified URL when something happens.
Infrastructure & DevOpsbeginner
API Key
A secret token passed in HTTP headers or query parameters to authenticate requests to an API service.
Headless BrowserHNSW

Try it now

Build with HMAC using one API.

Extract, index, and search any web content. First 1,000 requests free.

GET API KEY →
← Back to glossary