This guide will teach you how to verify the webhook message signatures sent in the header of webhook message requests. This enables you to verify that the message originated from dynamic and the message payload has not been tampered with since only Dynamic and you have access to the secret used to sign messages.

Below is a simple typescript function that takes in the webhook secret, signature, and payload; and returns a boolean value indicating if the signature is valid or not.

import * as crypto from "crypto";

export const verifySignature = ({
  secret,
  signature,
  payload,
}: {
  secret: string;
  signature: string;
  payload: any;
}) => {
  const payloadSignature = crypto
    .createHmac("sha256", secret)
    .update(JSON.stringify(payload))
    .digest("hex");
  const trusted = Buffer.from(`sha256=${payloadSignature}`, "ascii");
  const untrusted = Buffer.from(signature, "ascii");
  return crypto.timingSafeEqual(trusted, untrusted);
};

The following is a practical example of how to use the verifySignature function to verify a webhook message signature for a given payload.

The structure of the payload object matters; if the payload object is not structured in the manner in which the message was sent the signature verification will fail.

// webhook secret, unique per webhook
const secret = 'dyn_5LqRXtZsXit7Cjt9KktC8EGywoSkGSbGqtTud[S7AYd{LUTMcS38QRMT';

// signature sent in the header (x-dynamic-signature) of the webhook message
const signature = 'sha256=9c1eade367c30f371990918b8d79ecdd86ea2c8042849a1c22c94ad50b7d98fe';

// message payload sent in the body of the webhook POST request
const payload = {
  messageId: 'd487290b-9bbd-4b50-a5f5-6620634c8dd9',
  eventId: 'bfb51cec-345f-4539-b004-e3415223b86b',
  eventName: 'user.deleted',
  timestamp: '2024-05-31T17:21:14.890Z',
  webhookId: 'c51e4b22-193e-4989-9ce2-90851d57d861',
  userId: '001a4205-3d67-4956-a132-5ef41a06c78e',
  environmentId: 'ba1f6471-626b-45a1-ab63-c6bf4793a1c5',
  environmentName: 'sandbox',
  redelivery: true,
  data: {
    onboardingCompletedAt: '2024-01-22T20:38:29.049Z',
    metadata: {},
    createdAt: '2024-01-22T20:38:27.181Z',
    projectEnvironmentId: 'ba1f6471-626b-45a1-ab63-c6bf4793a1c5',
    id: '001a4205-3d67-4956-a132-5ef41a06c78e',
    firstVisit: '2024-01-22T20:38:27.169Z',
    email: '[email protected]',
    updatedAt: '2024-05-31T17:21:14.870Z',
    lastVisit: '2024-01-22T20:55:10.126Z',
    deletedAt: '2024-05-31T17:21:14.867Z',
  },
};

const isValid = verifySignature({ secret, signature, payload });
console.log('isValid', isValid);