Todos os artigos
POST webhook Laravel contornando CSRF via VerifyCsrfToken except, bytes getContent verificados com hash_equals num php artisan serve local.
LaravelPHPwebhook debugginglocal testing

Webhooks no Laravel: isenção CSRF, corpo bruto e verificação de assinatura

O Laravel protege cada rota web com CSRF. Provedores de webhook enviam POST sem cookie de sessão nem token CSRF — recebe 419 antes do controller. Solução: isenção CSRF direcionada e corpo bruto com $request->getContent().

Isentar rotas webhook do CSRF

Adicione a URI ao array $except em App\Http\Middleware\VerifyCsrfToken (Laravel 11+: middleware em bootstrap/app.php):

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

Isole exceções a paths server-to-server — nunca desative CSRF globalmente.

Ler corpo bruto para verificação de assinatura

Após contornar CSRF, leia 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);
}

Use getContent(), não all() ou input() — helpers Laravel não devolvem bytes assinados.

Verificar assinaturas antes da lógica de negócio

Extraia cabeçalhos, calcule digest do payload bruto, compare com hash_equals. Falha retorna 401. Veja guia de verificação de assinatura.

Configurar o túnel

  1. Inicie Laravel: php artisan serve --port=8000.
  2. Segundo terminal: npx portpreview 8000.
  3. Cole URL do túnel + path no dashboard.
  4. Com TrustProxies, confie nos headers forwarded do túnel.
  5. Dispare evento de teste.

Armadilhas comuns

Ler corpo duas vezes

getContent() após json() fica vazio. Leia uma vez, verifique, parse.

Ordem do middleware

Middleware global que parseia JSON antes do controller altera bytes. Isole rotas webhook.

Retries e idempotência

Persista IDs de evento — veja padrões de retry e idempotência.

Para aprofundar

Para fundamentos, leia noções de tunneling localhost e depuração local de webhooks. Para mecânica de assinatura, veja o guia de verificação de assinatura. Para handlers sem duplicatas, leia padrões de retry e idempotência. comece PortPreview grátis.

Perguntas frequentes

Por que o Laravel retorna 419 em POST webhook?
VerifyCsrfToken rejeita POST sem token CSRF válido. Adicione o path webhook a $except e verifique a assinatura.
getContent() ou all() para webhooks?
Use getContent() para verificação de assinatura. all() e input() devolvem dados parseados, não os bytes assinados.
Como testar webhooks Laravel localmente?
Execute php artisan serve, exponha com npx portpreview, cole a URL do túnel no dashboard e dispare eventos de teste.