Passer au contenu principal

Documentation Index

Fetch the complete documentation index at: https://help.withallo.com/llms.txt

Use this file to discover all available pages before exploring further.

Chaque requête webhook inclut une signature cryptographique vous permettant de vérifier qu’elle provient bien d’Allo. Sans vérification, un attaquant pourrait envoyer de faux événements à votre endpoint.

En-têtes de signature

Chaque POST webhook inclut trois en-têtes :
En-têteDescriptionExemple
webhook-idIdentifiant unique du messagemsg_2NfDKEm9sF8xK3pQr1Zt
webhook-timestampHorodatage Unix (secondes) de l’envoi du message1710510600
webhook-signatureUne ou plusieurs signatures HMAC-SHA256v1,K5oZfzN95Z3M+nrYOgGHfLGC7t8VjLtV...

Secret de signature

Lorsque vous créez un endpoint webhook, la réponse inclut un champ signing_secret. Ce secret a le format whsec_<clé_base64> et est utilisé pour vérifier les signatures. Conservez-le en sécurité — traitez-le comme un mot de passe. En cas de compromission, effectuez une rotation via l’API.

Algorithme de vérification

1

Extraire les en-têtes

Récupérez webhook-id, webhook-timestamp et webhook-signature des en-têtes de la requête.
2

Valider l'horodatage

Rejetez les requêtes dont l’horodatage s’écarte de plus de 5 minutes de l’heure actuelle de votre serveur. Cela prévient les attaques par rejeu.
3

Construire le contenu signé

Concaténez l’identifiant du webhook, l’horodatage et le corps brut de la requête avec des points :
{webhook-id}.{webhook-timestamp}.{raw_body}
4

Calculer la signature attendue

  1. Retirez le préfixe whsec_ de votre secret de signature.
  2. Décodez la chaîne restante en base64 pour obtenir les octets de la clé.
  3. Calculez le HMAC-SHA256 du contenu signé avec les octets de la clé.
  4. Encodez le résultat en base64.
5

Comparer les signatures

L’en-tête webhook-signature peut contenir plusieurs signatures séparées par des espaces (pour la rotation des secrets). Chacune a un préfixe v1,. Comparez votre signature calculée avec chacune d’elles. Si l’une correspond, la signature est valide.
Utilisez toujours le corps brut de la requête pour la vérification. Si votre framework parse le JSON puis le re-sérialise, la signature ne correspondra pas.

Exemples de code

const crypto = require("crypto");

function verifyWebhook(payload, headers, secret) {
  const webhookId = headers["webhook-id"];
  const webhookTimestamp = headers["webhook-timestamp"];
  const webhookSignature = headers["webhook-signature"];

  // Valider l'horodatage (tolérance de 5 minutes)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(webhookTimestamp)) > 300) {
    throw new Error("Timestamp too old");
  }

  // Construire le contenu signé
  const signedContent = `${webhookId}.${webhookTimestamp}.${payload}`;

  // Décoder le secret (retirer le préfixe "whsec_", décoder en base64)
  const secretBytes = Buffer.from(secret.split("_")[1], "base64");

  // Calculer le HMAC-SHA256
  const computed = crypto
    .createHmac("sha256", secretBytes)
    .update(signedContent)
    .digest("base64");

  // Comparer avec chaque signature de l'en-tête
  const signatures = webhookSignature
    .split(" ")
    .map((sig) => sig.split(",")[1]);

  if (!signatures.some((sig) => sig === computed)) {
    throw new Error("Invalid signature");
  }

  return JSON.parse(payload);
}

// Exemple avec Express.js
const express = require("express");
const app = express();

app.post(
  "/webhooks/allo",
  express.raw({ type: "application/json" }),
  (req, res) => {
    try {
      const event = verifyWebhook(
        req.body.toString(),
        req.headers,
        process.env.WEBHOOK_SECRET
      );
      console.log("Verified event:", event.topic);
      res.sendStatus(200);
    } catch (err) {
      console.error("Verification failed:", err.message);
      res.sendStatus(400);
    }
  }
);
Vérifiez toujours les signatures en production. Ignorer la vérification expose votre application à des événements webhook falsifiés.