X-Kairo-Signature con formato sha256={hex}. Calcule HMAC-SHA256 del cuerpo raw (UTF-8) con su webhook secret y compare el hex sin el prefijo.
- Python
- Node.js
- PHP
- Java
import hmac
import hashlib
def verify_kairo_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256,
).hexdigest()
received = signature_header.removeprefix("sha256=")
return hmac.compare_digest(expected, received)
# Flask ejemplo:
# raw_body = request.get_data()
# signature = request.headers.get("X-Kairo-Signature", "")
# if not verify_kairo_signature(raw_body, signature, WEBHOOK_SECRET):
# return "", 401
const crypto = require('crypto');
function verifyKairoSignature(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody, 'utf8')
.digest('hex');
const received = signatureHeader.replace(/^sha256=/, '');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex')
);
}
function verifyKairoSignature(string $rawBody, string $signatureHeader, string $secret): bool {
$expected = hash_hmac('sha256', $rawBody, $secret, false);
$received = str_starts_with($signatureHeader, 'sha256=')
? substr($signatureHeader, 7)
: $signatureHeader;
return hash_equals($expected, $received);
}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public static boolean verifyKairoSignature(
byte[] rawBody, String signatureHeader, String secret) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(rawBody);
StringBuilder sb = new StringBuilder();
for (byte b : hash) sb.append(String.format("%02x", b));
String received = signatureHeader.startsWith("sha256=")
? signatureHeader.substring(7) : signatureHeader;
return MessageDigest.isEqual(sb.toString().getBytes(), received.getBytes());
}
X-Kairo-Event o el campo event del payload.