Todos los artículos
Un POST webhook Laravel sorteando CSRF vía VerifyCsrfToken except, bytes getContent verificados con hash_equals en php artisan serve local.
LaravelPHPwebhook debugginglocal testing

Webhooks en Laravel: exención CSRF, cuerpo crudo y verificación de firma

Laravel protege cada ruta web con CSRF. Los proveedores webhook envían POST sin cookie de sesión ni token CSRF — obtienes 419 antes de que ejecute el controlador. Solución: exención CSRF dirigida y cuerpo crudo con $request->getContent().

Eximir rutas webhook del CSRF

Añade la URI al array $except en App\Http\Middleware\VerifyCsrfToken (Laravel 11+: middleware en bootstrap/app.php):

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

Limita las exenciones a rutas server-to-server — nunca desactives CSRF en toda la app.

Leer el cuerpo crudo para verificar firmas

Tras sortear CSRF, lee bytes intactos:

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);
}

Usa getContent(), no all() ni input() — los helpers de Laravel no devuelven los bytes firmados.

Verificar firmas antes de la lógica de negocio

Extrae cabeceras, calcula el digest del payload crudo y compara con hash_equals. Devuelve 401 si falla. Ver guía de verificación de firmas.

Configurar el túnel

  1. Inicia Laravel: php artisan serve --port=8000.
  2. Segundo terminal: npx portpreview 8000.
  3. Pega URL del túnel + ruta en el dashboard.
  4. Con TrustProxies, confía en headers forwarded del túnel.
  5. Dispara un evento de prueba.

Trampas comunes

Leer el cuerpo dos veces

getContent() tras json() devuelve vacío. Lee una vez, verifica, parsea.

Orden del middleware

Middleware global que parsea JSON antes del controlador altera bytes. Aísla rutas webhook.

Reintentos e idempotencia

Persiste IDs de evento — ver patrones de reintentos e idempotencia.

Para profundizar

Para los fundamentos, lea los fundamentos del tunneling localhost y depuración práctica de webhooks en local. Para la criptografía, consulte la guía de verificación de firmas. Para handlers sin duplicados, lea patrones de reintentos e idempotencia. empiece PortPreview gratis.

Preguntas frecuentes

¿Por qué Laravel devuelve 419 en POST webhook?
VerifyCsrfToken rechaza POST sin token CSRF válido. Añade la ruta webhook a $except y verifica la firma.
¿getContent() o all() para webhooks?
Usa getContent() para verificar firmas. all() e input() devuelven datos parseados, no los bytes firmados.
¿Cómo probar webhooks Laravel en local?
Ejecuta php artisan serve, expón con npx portpreview, pega la URL del túnel en el dashboard y dispara eventos de prueba.