Vérifier la signature
Chaque webhook est signé : c'est la seule preuve qu'il vient de Kelkun.
Le principe
Chaque envoi porte un en-tête de signature, au format des webhooks Stripe :
X-Kelkun-Signature: t=1792135957,v1=f418e566…t est l'horodatage de l'envoi, en secondes. v1 est le HMAC-SHA256, en hexadécimal, de la chaîne <t>.<corps brut>, avec pour clé le secret whsec_… entier que nous vous transmettons.
Vérifier un envoi
Lisez le corps brut
Avant tout parsing : un JSON réencodé ne donne pas la même signature.
Recalculez le HMAC
Et comparez-le à v1 en temps constant.
Refusez un envoi trop ancien
Un t écarté de plus de 5 minutes de votre horloge : c'est ce qui bloque un envoi rejoué.
import { createHmac, timingSafeEqual } from 'node:crypto'
export function isFromKelkun(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(
(header ?? '').split(',').map(part => part.split('='))
)
if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest()
const received = Buffer.from(v1, 'hex')
return received.length === expected.length && timingSafeEqual(received, expected)
}Le secret
Toutes vos entreprises partagent le même secret. Une nouvelle tentative est signée à nouveau, avec son propre t.
S'il doit changer, nous vous prévenons avant : l'ancien cesse de signer dès que nous le remplaçons.