Configuring Your Laravel 11 Application with Middleware and CSRF Token Exceptions

The following example demonstrates a professional configuration for a Laravel application. It showcases how to set up routes, middleware, and CSRF token exceptions for specific cases like handling Stripe webhooks.

bootstrap/app.php

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__ . '/../routes/web.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->validateCsrfTokens(except: [
                'stripe/webhook',
            ]);
    })
    ->withExceptions(function (Exceptions $exceptions) {
        //
    })->create();

routes/web.php

Route::post('/stripe/webhook', [StripeController::class, 'webhook'])->name('stripe.webhook');

app/controllers/StripeController.php

 public function webhook()
    {
        $endpoint_secret = config('stripe.wh'); // Use your Stripe webhook key

        $payload = file_get_contents('php://input');
        if (!$payload) {
            return response('Empty payload', 400);
        }

        $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? null;
        if (!$sig_header) {
            return response('Missing signature header', 400);
        }

        try {
            $event = \Stripe\Webhook::constructEvent(
                $payload,
                $sig_header,
                $endpoint_secret
            );
        } catch (\UnexpectedValueException $e) {
            // Invalid payload
            return response('Invalid payload', 400);
        } catch (\Stripe\Exception\SignatureVerificationException $e) {
            // Invalid signature
            return response('Invalid signature', 400);
        }

        $session = $event->data->object;

        try {
            switch ($event->type) {
                case 'checkout.session_completed':
                   // Do something if payment is completed, maybe call a function
                    break;
                default:
                    Log::info("Received unknown event type {$event->type}");
            }
        } catch (\Exception $e) {
            Log::error("Error processing Stripe webhook: {$e->getMessage()}");
            return response('Webhook handling error', 500);
        }

        return response('Webhook received', 200);
    }