Chaque webhook que Coffrify envoie à votre URL est signé. La signature vous permet de prouver deux choses avant de traiter l'événement : qu'il provient bien de Coffrify (et pas d'un tiers qui aurait deviné votre URL) et qu'il n'a pas été modifié en transit. Coffrify joint deux signatures en parallèle sur la même requête : le format Standard Webhooks, compatible avec les bibliothèques de vérification du marché, et le format Coffrify historique (legacy), conservé pour les intégrations existantes. Les deux reposent sur le même algorithme, HMAC-SHA256, et sur le secret de signature de votre endpoint. Vous n'êtes pas obligé de vérifier les deux : choisissez celui qui correspond à votre bibliothèque ou à votre code, et vérifiez-le systématiquement avant d'agir sur la charge utile.
Le secret de signature
Quand vous créez un endpoint via POST /v1/webhooks, la réponse contient un champ secret au format whsec_ suivi d'une chaîne hexadécimale. Ce secret n'est affiché qu'une seule fois : copiez-le immédiatement et stockez-le comme un identifiant sensible (variable d'environnement, coffre à secrets). Il sert de clé pour calculer et vérifier les signatures HMAC. Si vous le perdez, faites-le tourner depuis votre espace plutôt que de recréer l'endpoint.
Les en-têtes envoyés sur chaque livraison
Coffrify ajoute à chaque requête POST les en-têtes des deux formats. Vous trouverez donc côte à côte les en-têtes Standard Webhooks et les en-têtes Coffrify historiques :
| En-tête | Format | Contenu |
|---|---|---|
| webhook-id | Standard Webhooks | Identifiant unique de la livraison. Sert aussi à dédupliquer (idempotence côté réception). |
| webhook-timestamp | Standard Webhooks | Horodatage Unix en secondes au moment de la signature. |
| webhook-signature | Standard Webhooks | Signature(s) au format v1,<base64>. Plusieurs signatures peuvent être séparées par une espace. |
| X-Coffrify-Signature | Coffrify historique | Horodatage et signature au format t=<ts>,v1=<hex>. |
| X-Coffrify-Event-Id | Coffrify historique | Identifiant de l'événement. |
| X-Coffrify-Event-Type | Coffrify historique | Type de l'événement, par exemple transfer.downloaded. |
Format 1 : Standard Webhooks
Le format Standard Webhooks est une convention ouverte, prise en charge par de nombreuses bibliothèques de réception. La chaîne signée est la concaténation de l'identifiant de livraison, de l'horodatage et du corps brut de la requête, séparés par des points, dans cet ordre : webhook-id.webhook-timestamp.body. On calcule le HMAC-SHA256 de cette chaîne avec votre secret, on encode le résultat en base64, et on le préfixe par v1,. Pour vérifier, recalculez cette même valeur et comparez-la, en temps constant, à celle de l'en-tête webhook-signature.
Format 2 : Coffrify historique
Le format historique est transmis dans l'en-tête X-Coffrify-Signature. Sa valeur ressemble à t=1717000000,v1=ab12.... La partie t= porte l'horodatage Unix en secondes ; la partie v1= porte la signature en hexadécimal. Ici la chaîne signée est l'horodatage suivi d'un point puis du corps brut : timestamp.body. On calcule le HMAC-SHA256 avec votre secret et on encode le résultat en hexadécimal. L'horodatage est donc lu directement dans l'en-tête, contrairement au format Standard Webhooks où il arrive dans un en-tête séparé.
Tolérance d'horodatage et anti-rejeu
Comparer la signature ne suffit pas : un attaquant qui aurait capté une livraison valide pourrait la renvoyer plus tard. Pour s'en prémunir, vérifiez aussi que l'horodatage est récent. Coffrify recommande une tolérance de 5 minutes : rejetez toute requête dont l'horodatage (celui de webhook-timestamp ou celui de t= selon le format) s'écarte de plus de 300 secondes de l'heure courante de votre serveur. Pour une protection complète contre le rejeu, mémorisez le webhook-id des livraisons déjà traitées et ignorez les doublons : Coffrify réutilise le même identifiant lors des nouvelles tentatives d'une même livraison.
Vérifier en Node.js
L'exemple suivant gère les deux formats à partir du module natif crypto, sans dépendance. Il décode la clé depuis le secret whsec_, reconstruit la chaîne signée, applique l'encodage attendu (base64 ou hexadécimal) puis compare en temps constant. Adaptez la récupération du corps brut à votre framework (par exemple express.raw plutôt que express.json).
Vérifier en Python
Même logique en Python avec les modules hmac, hashlib et base64 de la bibliothèque standard. Pensez à passer le corps brut en octets (request.get_data() avec Flask, await request.body() avec FastAPI) et non un dictionnaire déjà désérialisé.
Tester votre vérification
Une fois votre endpoint en place, déclenchez une livraison de test signée avec POST /v1/webhooks/{id}/test. Vous recevrez une charge utile réelle, signée dans les deux formats, ce qui vous permet de valider votre code de vérification de bout en bout sans attendre un vrai événement.
/v1/webhooks/{id}/testEnvoie un événement de test signé vers l'URL de l'endpoint, avec les en-têtes Standard Webhooks et Coffrify historique.