トークンはZoho Webinarによって自動的に生成されます。
[コピー]をクリックしてトークンをコピーし、受信側アプリケーションに追加します。
現在のトークンが漏えいした場合は、[もう一度生成する]をクリックして新しいトークンを作成します。もう一度生成すると、前のトークンはすぐに無効になります。
本文には、Zoho WebinarがWebhook要求ごとに受信側アプリケーションへ送信するデータペイロードが含まれます。ペイロードは次の2つの形式のいずれかで送信できます。
受信側アプリケーションが、構造化された機械可読データを必要とする場合はJSON形式を使用します。ペイロードは、送信するイベントデータを表すキーと値のペアを含むJSONオブジェクトとして記述します。
受信側アプリケーションが、URLエンコードされた文字列として送信されるペイロードを必要とする場合は、フォームデータ形式を使用します。各値はURLエンコードされ、ペアは&で連結されます。
送信された本文
{'webinarId':'12345','event':'registration','email':'user@example.com'}
ヘッダー。
X-WEBINAR-SIGNATURE: a1b2c3d4e5f6...
Content-Type: application/json
Node.js
const crypto = require('crypto');
/**
* Verifies an X-WEBINAR-SIGNATURE header. Works for both JSON and
* form-data webhooks — just pass the raw request body.
*
* @param {string} rawBody Raw HTTP request body as received (JSON text or
* url-encoded form string); never parsed/re-serialized.
* @param {string} signatureHeader Value of the X-WEBINAR-SIGNATURE header.
* @param {string} secret The org's webhook signature key (token).
* @returns {boolean} True if the signature is valid.
*/
function verifySignature(rawBody, signatureHeader, secret) {
if (!signatureHeader || !secret) {
return false;
}
const body = rawBody || '';
const expected = crypto
.createHmac('sha256', secret)
.update(body, 'utf8')
.digest('hex'); // lowercase hex
const expectedBuf = Buffer.from(expected, 'utf8');
const receivedBuf = Buffer.from(signatureHeader.trim().toLowerCase(), 'utf8');
// Lengths must match for timingSafeEqual
if (expectedBuf.length !== receivedBuf.length) {
return false;
}
return crypto.timingSafeEqual(expectedBuf, receivedBuf);
}
// Example usage
const secret = 'your-webhook-signature-token';
// JSON webhook: rawBody is the JSON text as received
const jsonBody = '{'name':'Ann','id':42}';
// Form-data webhook: rawBody is the url-encoded form string as received
const formBody = 'name=Ann¬e=hi+there';
const signatureFromHeader = '...'; // X-WEBINAR-SIGNATURE value
const isValid = verifySignature(jsonBody, signatureFromHeader, secret);
console.log(isValid ? 'Signature is valid!' : 'Signature is invalid!');
Python
import hmac
import hashlib
def verify_signature(raw_body: str, signature_header: str, secret: str) -> bool:
'''
Verifies an X-WEBINAR-SIGNATURE header. Works for both JSON and
form-data webhooks -- just pass the raw request body.
:param raw_body: Raw HTTP request body as received (JSON text or
url-encoded form string); never parsed/re-serialized.
:param signature_header: Value of the X-WEBINAR-SIGNATURE header.
:param secret: The org's webhook signature key (token).
:return: True if the signature is valid.
'''
if not signature_header or not secret:
return False
body = raw_body or ''
expected = hmac.new(
secret.encode('utf-8'),
body.encode('utf-8'),
hashlib.sha256,
).hexdigest() # lowercase hex
# Constant-time comparison (header normalized to lowercase)
return hmac.compare_digest(expected, signature_header.strip().lower())
# Example usage
if __name__ == '__main__':
secret = 'your-webhook-signature-token'
# JSON webhook: raw_body is the JSON text as received
json_body = '{'name':'Ann','id':42}'
# Form-data webhook: raw_body is the url-encoded form string as received
form_body = 'name=Ann¬e=hi+there'
signature_from_header = '...' # X-WEBINAR-SIGNATURE value
is_valid = verify_signature(json_body, signature_from_header, secret)
print('Signature is valid!' if is_valid else 'Signature is invalid!')
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
public class WebinarSignatureValidator {
/**
* Verifies an X-WEBINAR-SIGNATURE header. Works for both JSON and
* form-data webhooks — just pass the raw request body.
*
* @param rawBody the raw HTTP request body as received (JSON text or
* url-encoded form string); never parsed/re-serialized
* @param signatureHeader value of the X-WEBINAR-SIGNATURE header
* @param secret the org's webhook signature key (token)
* @return true if the signature is valid
*/
public static boolean verifySignature(String rawBody, String signatureHeader, String secret) {
if (signatureHeader == null || signatureHeader.isEmpty() || secret == null) {
return false;
}
try {
String body = rawBody != null ? rawBody : '';
Mac mac = Mac.getInstance('HmacSHA256');
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), 'HmacSHA256'));
byte[] raw = mac.doFinal(body.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder(raw.length * 2);
for (byte b : raw) {
hex.append(Character.forDigit((b >>> 4) & 0xF, 16));
hex.append(Character.forDigit(b & 0xF, 16));
}
String expected = hex.toString();
// Constant-time comparison (header normalized to lowercase)
return MessageDigest.isEqual(
expected.getBytes(StandardCharsets.UTF_8),
signatureHeader.trim().toLowerCase().getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
return false;
}
}
// Example usage
public static void main(String[] args) {
String secret = 'your-webhook-signature-token';
// JSON webhook: rawBody is the JSON text as received
String jsonBody = '{\'name\':\'Ann\',\'id\':42}';
// Form-data webhook: rawBody is the url-encoded form string as received
String formBody = 'name=Ann¬e=hi+there';
String signatureFromHeader = '...'; // X-WEBINAR-SIGNATURE value
boolean valid = verifySignature(jsonBody, signatureFromHeader, secret);
System.out.println(valid ? 'Signature is valid!' : 'Signature is invalid!');
}
}