トークンはZoho Webセミナーによって自動生成されます
[コピー]をクリックしてトークンをコピーし、受信側アプリケーションに追加します
現在のトークンが漏洩した場合は、[再生成]をクリックして新しいトークンを作成します。再生成すると、以前のトークンは直ちに無効になります。
本文には、Zoho Webセミナーが各Webhook要求で受信側アプリケーションに送信するデータペイロードが含まれます。ペイロードは次の2つの形式のいずれかで送信できます。
JSON形式は、受信側アプリケーションが構造化された機械判読可能なデータを想定している場合に使用します。ペイロードは、送信するイベントデータを表すキーと値の組み合わせを含むJSONオブジェクトとして記述します。
フォームデータ形式は、受信側アプリケーションがURLエンコードされた文字列として送信されるペイロードを想定している場合に使用します。各値はURLエンコードされ、組み合わせは&で連結されます。
送信された本文
{'webinarId':'12345','event':'registration','メール':'ユーザー@例.com'}
ヘッダー。
X-Webセミナー-SIGNATURE: a1b2c3d4e5f6...
Content-Type: application/json
Node.js
const crypto = require('crypto');
/**
* Verifies an X-Webセミナー-SIGNATURE header. Works for both JSON and
* form-data webhooks — just pass the raw 要求 body.
*
* @param {string} rawBody Raw HTTP 要求 body as received (JSON text or
* url-encoded form string); never parsed/re-serialized.
* @param {string} signatureHeader Value of the X-Webセミナー-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&メモ=hi+there';
const signatureFromHeader = '...'; // X-Webセミナー-SIGNATURE value
const isValid = verifySignature(jsonBody, signatureFromHeader, secret);
console.log(isValid ? 'Signature is valid!' : 'Signature is invalid!');
Python
インポート hmac
インポート hashlib
def verify_signature(raw_body: str, signature_header: str, secret: str) -> bool:
'''
Verifies an X-Webセミナー-SIGNATURE header. Works for both JSON and
form-data webhooks -- just pass the raw 要求 body.
:param raw_body: Raw HTTP 要求 body as received (JSON text or
url-encoded form string); never parsed/re-serialized.
:param signature_header: Value of the X-Webセミナー-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&メモ=hi+there'
signature_from_header = '...' # X-Webセミナー-SIGNATURE value
is_valid = verify_signature(json_body, signature_from_header, secret)
print('Signature is valid!' if is_valid else 'Signature is invalid!')
Java
インポート javax.crypto.Mac;
インポート javax.crypto.spec.SecretKeySpec;
インポート java.nio.charset.StandardCharsets;
インポート java.security.MessageDigest;
public class WebinarSignatureValidator {
/**
* Verifies an X-Webセミナー-SIGNATURE header. Works for both JSON and
* form-data webhooks — just pass the raw 要求 body.
*
* @param rawBody the raw HTTP 要求 body as received (JSON text or
* url-encoded form string); never parsed/re-serialized
* @param signatureHeader value of the X-Webセミナー-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&メモ=hi+there';
String signatureFromHeader = '...'; // X-Webセミナー-SIGNATURE value
boolean valid = verifySignature(jsonBody, signatureFromHeader, secret);
System.out.println(valid ? 'Signature is valid!' : 'Signature is invalid!');
}
}