Webhooks - Verification
Verify webhook authenticity and handle URL validation.
Verify webhook authenticity and handle URL validation.
Verify webhook authenticity and handle URL validation.
Zoom provides two verification mechanisms:
When you configure a webhook endpoint, Zoom sends a validation request:
{
"event": "endpoint.url_validation",
"payload": {
"plainToken": "random_token_string"
}
}Hash the token with your webhook secret and respond:
const crypto = require('crypto');
app.post('/webhook', (req, res) => {
const { event, payload } = req.body;
if (event === 'endpoint.url_validation') {
const hashForValidation = crypto
.createHmac('sha256', WEBHOOK_SECRET_TOKEN)
.update(payload.plainToken)
.digest('hex');
return res.json({
plainToken: payload.plainToken,
encryptedToken: hashForValidation
});
}
// Handle other events...
res.status(200).send();
});Verify each webhook request is from Zoom:
| Header | Description | |--------|-------------| | `x-zm-signature` | Request signature | | `x-zm-request-timestamp` | Request timestamp |
const crypto = require('crypto');
function verifyWebhook(req) {
const signature = req.headers['x-zm-signature'];
const timestamp = req.headers['x-zm-request-timestamp'];
// Prefer raw body bytes captured by your framework to avoid JSON re-serialization mismatches.
const body = req.rawBody ? req.rawBody.toString('utf8') : JSON.stringify(req.body);
const message = `v0:${timestamp}:${body}`;
const hash = crypto
.createHmac('sha256', WEBHOOK_SECRET_TOKEN)
.update(message)
.digest('hex');
const expectedSignature = `v0=${hash}`;
return signature === expectedSignature;
}