Webhook - Documentation technique
Corps de chaque événement Webhook
Différents paramètres peuvent être retrouvés dans le body de retour du Webhook :
eventId : Permet d'identifier un évènement de manière unique et de ne pas retraiter le même évènement.
type : Correspond au type de webhook envoyé.
data : Objet de retour lié au type du webhook.
Mode d'authentification
La vérification de l'émetteur se fait au moyen d'une signature HMAC SHA-256. Le retour Webhook est composé de plusieurs headers :
x-webhook-signature : Signature HMAC SHA-256, cette signature est une concaténation du body de la réponse et du timestamp présent dans le x-webhook-delivery-ts-ms avec un point au milieu ce qui donne le format suivant à signer "body.timestamp"
x-webhook-delivery-ts-ms : Epoch en milliseconde de l'envoi du Webhook depuis notre système.
Exemple
Clé secrète partagée : thisIsMySecretKey
Evénement webhook reçu :
Headers :
x-webhook-signature : 20DD74DAF33FA144781ACA298242C627414D1DFC75CB748B269F95AD61F63ABD
x-webhook-delivery-ts-ms : 1655816087318
Body :
{
"eventId": "7c9f8528-b83a-424f-9817-922a4344f59c",
"type": "BLACKLIST_PEP_RISK_STATUS_UPDATE",
"data": {
"type": "BLACKLIST",
"riskFolderId": "62892db4e4098caee87d3f2a",
"personRef": {
"sourceName": "sourceName",
"externalRefId": "externalId"
},
"lastFlowName": "flowName",
"lastFlowId": "62892db4e4098caee87abcde",
"maxMatchingScore": 85,
"status": {
"authorLogin": "user2@example.com",
"date": "2022-06-21T11:01:11.123503660Z",
"state": "MATCH"
}
}
}
Exemple en Kotlin pour obtenir la signature à partir du body, timestamp et secret :
fun hmacExample() {
val timestamp = 1655816087318
val key = "thisIsMySecretKey".toByteArray()
val bodyJson = "{\"eventId\":\"7c9f8528-b83a-424f-9817-922a4344f59c\",\"type\":\"BLACKLIST_PEP_RISK_STATUS_UPDATE\",\"data\":{\"type\":\"BLACKLIST\",\"riskFolderId\":\"62892db4e4098caee87d3f2a\",\"personRef\":{\"sourceName\":\"sourceName\",\"externalRefId\":\"externalId\"},\"lastFlowName\":\"flowName\",\"lastFlowId\":\"62892db4e4098caee87abcde\",\"maxMatchingScore\":85,\"status\":{\"authorLogin\":\"user2@example.com\",\"date\":\"2022-06-21T11:01:11.123503660Z\",\"state\":\"MATCH\"}}}"
val algo = "HmacSHA256"
val hMacSHA256: Mac = Mac.getInstance(algo)
val secretKey = SecretKeySpec(key, algo)
hMacSHA256.init(secretKey)
val data: ByteArray = hMacSHA256.doFinal(("$bodyJson.$timestamp").toByteArray())
val hmac = StringBuilder()
data.forEach { hmac.append(String.format("%02X", it)) }
println(hmac)
}
Même exemple en Java :
public static void hmacExample() throws NoSuchAlgorithmException, InvalidKeyException {
long timestamp = 1655816087318L;
byte[] key = "thisIsMySecretKey".getBytes();
String bodyJson = "{\"eventId\":\"7c9f8528-b83a-424f-9817-922a4344f59c\",\"type\":\"BLACKLIST_PEP_RISK_STATUS_UPDATE\",\"data\":{\"type\":\"BLACKLIST\",\"riskFolderId\":\"62892db4e4098caee87d3f2a\",\"personRef\":{\"sourceName\":\"sourceName\",\"externalRefId\":\"externalId\"},\"lastFlowName\":\"flowName\",\"lastFlowId\":\"62892db4e4098caee87abcde\",\"maxMatchingScore\":85,\"status\":{\"authorLogin\":\"user2@example.com\",\"date\":\"2022-06-21T11:01:11.123503660Z\",\"state\":\"MATCH\"}}}";
String algo = "HmacSHA256";
Mac hMacSHA256 = Mac.getInstance(algo);
SecretKeySpec secretKey = new SecretKeySpec(key, algo);
hMacSHA256.init(secretKey);
byte[] data = hMacSHA256.doFinal((bodyJson + "." + timestamp).getBytes());
StringBuilder hmac = new StringBuilder();
for (byte b : data) {
hmac.append(String.format("%02X", b));
}
System.out.println(hmac);
}