WRMS ProDocs

Verifying signatures

Check the X-WRMS-Signature header so your endpoint only accepts requests that really came from WRMS Pro, and rejects replays.

Audience:Developer

Anyone can send a request to your endpoint. The signature proves it came from WRMS Pro, using the secret only you and WRMS Pro know.

How the signature is made

The X-WRMS-Signature header looks like this:

t=1790000000000,v1=3b0f8f0a4c…
  • t is the time the request was signed, in milliseconds since 1 January 1970 (UTC).
  • v1 is the HMAC-SHA256 of the string <t>.<raw request body>, keyed with your webhook's signing secret, written as lowercase hexadecimal.

Verify it

  1. Read the raw request body exactly as received, before any JSON parsing.
  2. Split the header on , and = to get t and v1.
  3. Reject the request if t is more than 5 minutes from your current time.
  4. Compute HMAC-SHA256 of t + "." + rawBody with your secret.
  5. Compare it with v1 using a constant-time comparison. Reject if they differ.
  6. Respond 2xx quickly, then process the event.
import { createHmac, timingSafeEqual } from 'node:crypto';

export function verifyWrmsSignature(rawBody, header, secret, toleranceMs = 5 * 60 * 1000) {
  const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')));
  const t = Number(parts.t);
  const v1 = (parts.v1 ?? '').toLowerCase();
  if (!Number.isFinite(t) || !v1) return false;
  if (Math.abs(Date.now() - t) > toleranceMs) return false;

  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(v1);
  return a.length === b.length && timingSafeEqual(a, b);
}

Common mistakes

  • Parsing the JSON first. Re-serialising changes whitespace and key order, so the signature no longer matches. Sign-check the raw bytes.
  • Treating t as seconds. It is milliseconds.
  • Using the wrong secret after rotating it. Rotation takes effect immediately.
  • Clock drift. Keep your server's clock synchronised, or requests fall outside the 5-minute window.

Avoid processing twice

A retried delivery has the same X-WRMS-Delivery ID and the same event id. Store IDs you have processed and skip repeats.

Still need help?

Email support@wrmspro.com or use the contact form. Signed-in users can also send a request from Settings → Support.

On this page