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 requete webhook inclut une signature cryptographique pour que vous puissiez verifier qu’elle provient bien d’Allo. Sans verification, un attaquant pourrait envoyer de faux evenements a votre endpoint.

En-tetes de signature

Chaque requete POST webhook inclut trois en-tetes :
En-teteDescriptionExemple
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 creez un endpoint webhook, la reponse inclut un champ signing_secret. Ce secret a le format whsec_<base64key> et est utilise pour verifier les signatures. Stockez-le de maniere securisee — traitez-le comme un mot de passe. S’il est compromis, effectuez une rotation via l’API.

Algorithme de verification

1

Extraire les en-tetes

Recuperez webhook-id, webhook-timestamp et webhook-signature depuis les en-tetes de la requete.
2

Valider l'horodatage

Rejetez les requetes dont l’horodatage est eloigne de plus de 5 minutes de l’heure actuelle de votre serveur. Cela empeche les attaques par rejeu.
3

Construire le contenu signe

Concatenez l’identifiant du webhook, l’horodatage et le corps brut de la requete avec des points :
{webhook-id}.{webhook-timestamp}.{raw_body}
4

Calculer la signature attendue

  1. Supprimez le prefixe whsec_ de votre secret de signature.
  2. Decodez en base64 la chaine restante pour obtenir les octets de la cle.
  3. Calculez le HMAC-SHA256 du contenu signe avec les octets de la cle.
  4. Encodez le resultat en base64.
5

Comparer les signatures

L’en-tete webhook-signature peut contenir plusieurs signatures separees par des espaces (pour la rotation des secrets). Chacune a un prefixe v1,. Comparez votre signature calculee avec chacune d’entre elles. Si l’une correspond, la signature est valide.
Utilisez toujours le corps brut de la requete pour la verification. Si votre framework parse le JSON et le re-serialise, 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"];

  // Validate timestamp (5-minute tolerance)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(webhookTimestamp)) > 300) {
    throw new Error("Timestamp too old");
  }

  // Build signed content
  const signedContent = `${webhookId}.${webhookTimestamp}.${payload}`;

  // Decode secret (strip "whsec_" prefix, base64-decode)
  const secretBytes = Buffer.from(secret.split("_")[1], "base64");

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

  // Compare against each signature in the header
  const signatures = webhookSignature
    .split(" ")
    .map((sig) => sig.split(",")[1]);

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

  return JSON.parse(payload);
}

// Express.js example
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);
    }
  }
);
Verifiez toujours les signatures en production. Ignorer la verification expose votre application a des evenements webhook usurpes.