Tous les articles
Tester les webhooks Linear sur localhost en toute sécurité
Linearwebhookslocalhostdeveloper integrations

Tester les webhooks Linear sur localhost en toute sécurité

Un service distant ne peut pas joindre localhost. Le tunnel fournit une URL HTTPS publique et transmet chaque requête au serveur local, avec les vrais headers et le body original. Conservez le body brut avant tout parseur JSON. Vérifiez la signature, validez les champs attendus, enregistrez la livraison durablement, puis seulement lancez le traitement métier.

Comprendre le flux Linear vers une application locale

Un service distant ne peut pas joindre localhost. Le tunnel fournit une URL HTTPS publique et transmet chaque requête au serveur local, avec les vrais headers et le body original. >documentation officielle

1. Créer un endpoint qui conserve le body brut

Conservez le body brut avant tout parseur JSON. Vérifiez la signature, validez les champs attendus, enregistrez la livraison durablement, puis seulement lancez le traitement métier.

import express from "express";
import crypto from "node:crypto";

const app = express();
const secret = process.env.LINEAR_WEBHOOK_SECRET;

app.post(
  "/webhooks/linear",
  express.raw({ type: "application/json", limit: "1mb" }),
  async (req, res) => {
    const rawBody = req.body;
    const signature = req.get("linear-signature");

    if (!verifyLinearSignature(signature, rawBody, secret)) {
      return res.sendStatus(401);
    }

    let payload;
    try {
      payload = JSON.parse(rawBody.toString("utf8"));
    } catch {
      return res.sendStatus(400);
    }

    if (!Number.isFinite(payload.webhookTimestamp) ||
        Math.abs(Date.now() - payload.webhookTimestamp) > 60_000) {
      return res.sendStatus(401);
    }

    const deliveryId = req.get("linear-delivery") || payload.webhookId;
    if (!deliveryId) return res.sendStatus(400);

    try {
      await recordAndEnqueueOnce(deliveryId, payload);
      return res.sendStatus(200);
    } catch (error) {
      console.error("Linear webhook persistence failed", error);
      return res.sendStatus(500);
    }
  }
);

app.use(express.json());
app.listen(3000);

Conservez le body brut avant tout parseur JSON. Vérifiez la signature, validez les champs attendus, enregistrez la livraison durablement, puis seulement lancez le traitement métier. >documentation officielle

2. Exposer le port local en HTTPS

Démarrez le serveur, ouvrez le tunnel dans un second terminal et gardez le processus actif pendant le test. Une réponse 401 à une requête non signée confirme que le routage fonctionne.

npx portpreview 3000
https://example.portpreview.dev/webhooks/linear

Démarrez le serveur, ouvrez le tunnel dans un second terminal et gardez le processus actif pendant le test. Une réponse 401 à une requête non signée confirme que le routage fonctionne.

3. Configurer le webhook dans Linear

Enregistrez l’URL HTTPS complète, limitez l’abonnement aux événements utiles et déclenchez un cas réel dans un environnement de test. Stockez le secret hors du dépôt.

Enregistrez l’URL HTTPS complète, limitez l’abonnement aux événements utiles et déclenchez un cas réel dans un environnement de test. Stockez le secret hors du dépôt.

Vérifier la signature sur les octets exacts

Calculez le HMAC avec le secret du webhook et les données exactes définies par le fournisseur. Utilisez une comparaison en temps constant et ne journalisez jamais le secret.

function verifyLinearSignature(signature, rawBody, secret) {
  if (!secret || typeof signature !== "string" ||
      !/^[0-9a-f]{64}$/i.test(signature)) {
    return false;
  }

  const expected = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest();
  const actual = Buffer.from(signature, "hex");

  return actual.length === expected.length &&
    crypto.timingSafeEqual(actual, expected);
}

Calculez le HMAC avec le secret du webhook et les données exactes définies par le fournisseur. Utilisez une comparaison en temps constant et ne journalisez jamais le secret. >guide pratique

Bloquer les attaques par rejeu

Contrôlez l’horodatage après la signature et rejetez les messages trop anciens. Une horloge système synchronisée évite les faux rejets.

Contrôlez l’horodatage après la signature et rejetez les messages trop anciens. Une horloge système synchronisée évite les faux rejets.

Comprendre le payload et les identifiants de livraison

Traitez uniquement les types connus, acceptez les champs additionnels et utilisez un identifiant de livraison stable pour la déduplication.

Traitez uniquement les types connus, acceptez les champs additionnels et utilisez un identifiant de livraison stable pour la déduplication.

Répondre vite et traiter de façon idempotente

Réservez l’identifiant et créez le job dans une transaction atomique avant de répondre 200. Retournez une erreur si le stockage durable est indisponible.

Réservez l’identifiant et créez le job dans une transaction atomique avant de répondre 200. Retournez une erreur si le stockage durable est indisponible. >guide pratique

Tester tout le parcours en local

  1. Démarrez le serveur, ouvrez le tunnel dans un second terminal et gardez le processus actif pendant le test. Une réponse 401 à une requête non signée confirme que le routage fonctionne.
  2. Enregistrez l’URL HTTPS complète, limitez l’abonnement aux événements utiles et déclenchez un cas réel dans un environnement de test. Stockez le secret hors du dépôt.
  3. Calculez le HMAC avec le secret du webhook et les données exactes définies par le fournisseur. Utilisez une comparaison en temps constant et ne journalisez jamais le secret.
  4. Réservez l’identifiant et créez le job dans une transaction atomique avant de répondre 200. Retournez une erreur si le stockage durable est indisponible.

Vérifiez le routage, les headers, la signature, le délai de réponse et l’idempotence. Les requêtes synthétiques servent surtout à tester les chemins de rejet.

Diagnostiquer les échecs de livraison Linear

  • Démarrez le serveur, ouvrez le tunnel dans un second terminal et gardez le processus actif pendant le test. Une réponse 401 à une requête non signée confirme que le routage fonctionne.
  • Calculez le HMAC avec le secret du webhook et les données exactes définies par le fournisseur. Utilisez une comparaison en temps constant et ne journalisez jamais le secret.
  • Contrôlez l’horodatage après la signature et rejetez les messages trop anciens. Une horloge système synchronisée évite les faux rejets.
  • En cas d’échec, contrôlez le chemin POST, le port du tunnel, le body brut, le secret, l’horloge et la latence de la base de données.

>guide pratique

Checklist de sécurité pour le développement et la production

  • Exigez HTTPS, limitez taille et méthode, protégez les secrets, masquez les données sensibles dans les logs et supprimez les URLs de test obsolètes.
  • Conservez le body brut avant tout parseur JSON. Vérifiez la signature, validez les champs attendus, enregistrez la livraison durablement, puis seulement lancez le traitement métier.
  • Réservez l’identifiant et créez le job dans une transaction atomique avant de répondre 200. Retournez une erreur si le stockage durable est indisponible.

Exigez HTTPS, limitez taille et méthode, protégez les secrets, masquez les données sensibles dans les logs et supprimez les URLs de test obsolètes. >guide pratique

Questions fréquentes

Comment tester un webhook Linear sur localhost ?
Démarrez le serveur, ouvrez le tunnel dans un second terminal et gardez le processus actif pendant le test. Une réponse 401 à une requête non signée confirme que le routage fonctionne.
Comment vérifier la signature d’un webhook Linear ?
Calculez le HMAC avec le secret du webhook et les données exactes définies par le fournisseur. Utilisez une comparaison en temps constant et ne journalisez jamais le secret.
Pourquoi Linear renvoie-t-il le webhook ?
Réservez l’identifiant et créez le job dans une transaction atomique avant de répondre 200. Retournez une erreur si le stockage durable est indisponible.
Quelle clé utiliser pour assurer l’idempotence ?
Traitez uniquement les types connus, acceptez les champs additionnels et utilisez un identifiant de livraison stable pour la déduplication.