Webhooks
Signature & vérification HMAC
Valider les payloads webhook pour rejeter les requêtes non authentifiées.
Chaque requête webhook sortante est signée avec HMAC-SHA256. Vérifiez cette signature avant de traiter le payload - cela protège contre les requêtes forgées.
Header de signature
Coffrify-Signature: t=1716897600,v1=a1b2c3d4e5f6...Le header contient le timestamp `t` (unix seconds) et la signature `v1` (hex HMAC-SHA256).
Algorithme de vérification
- Extraire `t` et `v1` du header `Coffrify-Signature`.
- Construire la chaîne à signer : `{t}.{corps_brut}`.
- Calculer HMAC-SHA256 de cette chaîne avec votre `secret` webhook.
- Comparer (en constant-time) avec `v1`.
- Vérifier que `|now() - t| < 300` (5 min) pour rejeter les replays.
Implémentation
typescript
import crypto from 'node:crypto';
export function verifyWebhook(
rawBody: string,
signature: string,
secret: string,
): boolean {
const [tPart, v1Part] = signature.split(',');
const t = tPart.split('=')[1];
const v1 = v1Part.split('=')[1];
// Rejeter si timestamp > 5 min
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const payload = `${t}.${rawBody}`;
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(v1, 'hex'),
);
}Exemple Express.js
webhook-handler.tstypescript
import express from 'express';
import { verifyWebhook } from './verify';
const app = express();
app.post('/webhooks/coffrify',
express.raw({ type: 'application/json' }), // corps brut obligatoire
(req, res) => {
const sig = req.headers['coffrify-signature'] as string;
if (!verifyWebhook(req.body.toString(), sig, process.env.WEBHOOK_SECRET!)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString());
// traitement async...
res.sendStatus(200);
},
);