Coffrifydocs
⌘K
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

  1. Extraire `t` et `v1` du header `Coffrify-Signature`.
  2. Construire la chaîne à signer : `{t}.{corps_brut}`.
  3. Calculer HMAC-SHA256 de cette chaîne avec votre `secret` webhook.
  4. Comparer (en constant-time) avec `v1`.
  5. 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);
  },
);