Laravel chroni każdą trasę web CSRF. Dostawcy webhooków wysyłają POST bez cookie sesji i tokenu CSRF — dostajesz 419 przed kontrolerem. Rozwiązanie: wyjątek CSRF i surowe body przez $request->getContent().
Wyłącz CSRF dla tras webhook
Dodaj URI do tablicy $except w App\Http\Middleware\VerifyCsrfToken (Laravel 11+: middleware w bootstrap/app.php):
protected $except = [
'webhooks/stripe',
'webhooks/*',
];
Wąskie wyjątki — tylko ścieżki server-to-server, nigdy globalnie CSRF.
Czytaj surowe body do weryfikacji podpisu
Po obejściu CSRF czytaj nietknięte bajty:
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);
}
Użyj getContent(), nie all() ani input() — helpery Laravel nie zwracają podpisanych bajtów.
Weryfikuj podpisy przed logiką biznesową
Wyciągnij nagłówki, oblicz digest z surowego payloadu, porównaj hash_equals. Przy błędzie 401. Zobacz przewodnik weryfikacji podpisu.
Skonfiguruj tunel
- Uruchom Laravel:
php artisan serve --port=8000. - Drugi terminal:
npx portpreview 8000. - Wklej URL tunelu + ścieżkę w dashboardzie.
- Z
TrustProxiesufaj nagłówkom forwarded z tunelu. - Wywołaj zdarzenie testowe.
Typowe pułapki
Podwójne czytanie body
getContent() po json() jest puste. Czytaj raz, weryfikuj, parsuj.
Kolejność middleware
Globalny parser JSON przed kontrolerem zmienia bajty. Izoluj trasy webhook.
Retry i idempotencja
Persistuj ID zdarzeń — zobacz wzorce retry i idempotencji.
Więcej
Podstawy znajdziesz w podstawach tunelowania localhost oraz praktycznym lokalnym debugowaniu webhooków. Mechanika podpisu — w przewodniku weryfikacji podpisu. Obsługa bez duplikatów — w wzorach retry i idempotencji. zacznij PortPreview za darmo.
