Tous les articles
Un POST webhook Laravel contournant CSRF via VerifyCsrfToken except, avec octets getContent vérifiés par hash_equals sur php artisan serve local.
LaravelPHPwebhook debugginglocal testing

Webhooks Laravel : exemption CSRF, corps brut et vérification de signature

Laravel active la protection CSRF sur chaque route web. Les providers webhook envoient des POST sans cookie ni token CSRF — vous obtenez un 419 avant le contrôleur. Solution : exemption CSRF ciblée et corps brut via $request->getContent().

Exempter les routes webhook du CSRF

Ajoutez l'URI au tableau $except de App\Http\Middleware\VerifyCsrfToken (ou la classe middleware dans bootstrap/app.php sur Laravel 11+) :

protected $except = [
    'webhooks/stripe',
    'webhooks/*',
];

Limitez les exemptions aux chemins server-to-server — ne désactivez jamais CSRF globalement.

Lire le corps brut pour la signature

Une fois CSRF contourné, lisez les octets intacts :

public function handle(Request $request)
{
    $payload = $request->getContent(); // raw string
    $signature = $request->header('Stripe-Signature', '');

    if (!$this->verifySignature($payload, $signature)) {
        return response('', 401);
    }

    $event = json_decode($payload, true, 512, JSON_THROW_ON_ERROR);
    $this->processEvent($event);
    return response('', 200);
}

Utilisez getContent(), pas all() ou input() — les helpers Laravel ne renvoient pas les octets signés par le provider.

Vérifier les signatures avant la logique métier

Extrayez les en-têtes, calculez le digest depuis le payload brut et comparez avec hash_equals. Renvoyez 401 si échec. Voir le guide de vérification de signature.

Configurer le tunnel

  1. Lancez Laravel : php artisan serve --port=8000.
  2. Terminal suivant : npx portpreview 8000.
  3. Collez l'URL tunnel + chemin dans le dashboard provider.
  4. Avec TrustProxies, approuvez les en-têtes forwarded du tunnel.
  5. Déclenchez un événement test.

Pièges courants

Lecture double du corps

getContent() après json() renvoie vide. Lisez une fois, vérifiez, parsez.

Ordre du middleware

Un middleware global qui parse le JSON avant le contrôleur altère les octets. Isolez les routes webhook.

Retries et idempotence

Persistez les IDs d'événement — voir patterns retry et idempotence.

Pour aller plus loin

Pour les bases, lisez les bases du tunneling localhost et le débogage webhook en local. Pour la cryptographie, consultez le guide de vérification de signature. Pour les handlers sans doublons, voyez les patterns retry et idempotence. commencez PortPreview gratuitement.

Questions fréquentes

Pourquoi Laravel renvoie 419 sur les POST webhook ?
VerifyCsrfToken rejette les POST sans token CSRF valide. Ajoutez le chemin webhook à $except, puis vérifiez la signature.
getContent() ou all() pour les webhooks ?
Utilisez getContent() pour la signature. all() et input() renvoient des données parsées qui ne correspondent pas aux octets signés.
Comment tester les webhooks Laravel en local ?
Lancez php artisan serve, exposez avec npx portpreview, collez l'URL tunnel dans le dashboard et déclenchez des événements test.