Hi everyone,
I’m running into an issue with Zoom webhook validation and I’m hoping someone can clarify what’s happening.
-
When I expose my service using ngrok, Zoom’s webhook URL validation (
endpoint.url_validation
) works fine. -
But when I put the same service behind my API Gateway (Express.js gateway forwarding requests to microservices), Zoom responds with “validation failed”.
Here’s some context:
-
My Sessions service has
express.json()
enabled globally, and I can’t disable it for just this route. -
For webhook signature validation, I’m building the message like this:
const message = `v0:${req.headers['x-zm-request-timestamp']}:${JSON.stringify(req.body)}`;
- This works with ngrok directly, but fails when the request goes through my gateway.
My guess: the gateway or express.json() is modifying the body (parsing and re-stringifying), so the payload is no longer byte-for-byte identical to what Zoom sent. This would explain why signature validation fails.
Questions:
-
Is my understanding correct that Zoom requires the exact raw request body for signature and URL validation?
-
If so, what’s the best practice for handling this in an Express.js microservices setup where
express.json()
is already in use globally?-
Should I capture the raw body using the
verify
option inexpress.json()
? -
Or should I route Zoom’s webhook through
express.raw({ type: "application/json" })
at the gateway and then forward it untouched?
-
Any guidance or confirmation would be really helpful. Thanks!