Traduite de l'anglais. En cas de différence, la page en anglais fait foi. Lire en anglais
Vérifier les signatures
Prouvez qu'un webhook vient bien de Nembol, avec des vérificateurs prêts à copier dans quatre langages.
Chaque livraison porte :
X-Nembol-Signature: t=1784900412,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bdt: horodatage Unix de la tentative de livraison.v1: HMAC-SHA256, calculé avec le secret de signature de votre endpoint, sur la chaîne"<t>.<raw_body>". Pendant une période de rotation du secret, vous pouvez voir deux entréesv1=. Acceptez la livraison si l'une d'elles correspond.
Étapes de vérification : (1) lisez le corps brut de la requête, avant tout parsing
JSON ou toute transformation par un middleware ; (2) calculez le HMAC attendu ;
(3) comparez en temps constant ; (4) rejetez si |now − t| dépasse 5
minutes (protection contre le rejeu).
import crypto from 'node:crypto';
// Express: app.post('/webhook', express.raw({ type: 'application/json' }), handler)
export function verifyNembolSignature(rawBody, signatureHeader, secret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((kv) => kv.split('=', 2)),
);
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${rawBody}`)
.digest('hex');
return signatureHeader
.split(',')
.filter((kv) => kv.startsWith('v1='))
.some((kv) => {
const candidate = Buffer.from(kv.slice(3), 'hex');
const exp = Buffer.from(expected, 'hex');
return candidate.length === exp.length && crypto.timingSafeEqual(candidate, exp);
});
}L'erreur classique : vérifier à partir d'un corps JSON resérialisé. Le JSON parsé puis re-stringifié par votre framework ne sera pas identique octet pour octet à ce que Nembol a envoyé, et la signature ne correspondra pas. Conservez toujours les octets bruts.
Dernière mise à jour le 20 octobre 2026
Besoin d'aide ?
Écrivez-nous et une personne vous répond, généralement sous un jour ouvré.