Can someone help me de-bug my code for webhook authorization/long term use?

I created a URL in Pipedream to forward webhook requests to, which then forwards the body to Power Automate. In Pipedream the validation shows as successful returning the response Zoom needs, but Zoom validation is still failing. Anyone know what is wrong with my code?

[:warning: Suspicious Content] import axios from “axios”;
import crypto from “crypto”;

export default defineComponent({
async run({ event }) {
const ZOOM_WEBHOOK_SECRET_TOKEN = process.env.ZOOM_WEBHOOK_SECRET_TOKEN;
const POWER_AUTOMATE_URL = process.env.POWER_AUTOMATE_URL;

if (!ZOOM_WEBHOOK_SECRET_TOKEN || !POWER_AUTOMATE_URL) {
  return {
    status: 500,
    body: "Missing environment variables"
  };
}

const headers = {};
for (const [key, value] of Object.entries(event.headers || {})) {
  headers[key.toLowerCase()] = value;
}

const timestamp = headers["x-zm-request-timestamp"];
const signature = headers["x-zm-signature"];

if (!timestamp || !signature) {
  return {
    status: 400,
    body: "Missing required Zoom headers"
  };
}

const body = event.body;

// For signature validation
const rawBodyString = JSON.stringify(body);
const message = `v0:${timestamp}:${rawBodyString}`;
const computedHash = crypto
  .createHmac("sha256", ZOOM_WEBHOOK_SECRET_TOKEN)
  .update(message)
  .digest("hex");

const expectedSignature = `v0=${computedHash}`;
if (signature !== expectedSignature) {
  return {
    status: 401,
    headers: { "Content-Type": "application/json" },
    body: { message: "Unauthorized request to Zoom Webhook." }
  };
}

// ✅ Immediate return for endpoint validation
if (body.event === "endpoint.url_validation") {
  const plainToken = body?.payload?.plainToken;
  const encryptedToken = crypto
    .createHmac("sha256", ZOOM_WEBHOOK_SECRET_TOKEN)
    .update(plainToken)
    .digest("hex");

  return {
    status: 200,
    headers: { "Content-Type": "application/json" },
    body: {
      plainToken,
      encryptedToken
    }
  };
}

// ✅ Forward valid events to Power Automate (after validation)
try {
  await axios.post(POWER_AUTOMATE_URL, body, {
    headers: { "Content-Type": "application/json" }
  });
} catch (err) {
  console.error("Error forwarding to Power Automate:", err.message);
}

return {
  status: 200,
  headers: { "Content-Type": "application/json" },
  body: { message: "Authorized request to Zoom Webhook." }
};

}
});

I am not too familiar with node.js, but I would recommend you using console.log to verify 1-) What is coming in from Zoom and 2-) your built response before you send it, just to validate that the logic is being followed as you expect. I’ve found this sample on GitHub of a working webhook-sample if you want to take a look. But it is using ngrok as the endpoint instead of pipedream, but might be worth taking a look: GitHub - zoom/webhook-sample: Receive Zoom webhooks.

1 Like