Learn how to build secure, production-ready webhooks in Laravel. We cover HMAC signature verification and asynchronous processing to keep your API resilient.
Previously in this course, we covered Integrating Third-Party Services in Laravel: A Practical Guide. While that lesson focused on outbound requests, this lesson shifts the perspective to inbound data: webhooks.
Webhooks are the "reverse" of standard API calls. Instead of your application polling a service for changes, the service pushes data to you. When building a project board that syncs with external tools like GitHub or Jira, you need a way to receive these events reliably and securely.
A webhook is simply an HTTP POST request sent to your server. Because these requests originate from the public internet, they are inherently untrusted. To handle them effectively, you must follow three core principles:
Since webhooks are external, they bypass your standard web middleware (like VerifyCsrfToken). You should define these in routes/api.php or a dedicated routes/webhooks.php file that doesn't include CSRF middleware.
PHP#6A9955">// routes/api.php Route::post('/webhooks/github', [GitHubWebhookController::class, 'handle']);
In your controller, avoid putting business logic here. Your only goal is to validate the request and hand it off to a queued job.
Never trust a raw JSON payload. Most services provide a signature—usually a hash of the payload body signed with a secret key—in the request headers. You must use this to verify the request's authenticity.
If you don't verify the signature, any malicious actor could spoof events and manipulate your database.
PHPnamespace App\Http\Controllers; use Illuminate\Http\Request; use App\Jobs\ProcessGitHubWebhook; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class GitHubWebhookController extends Controller { public function handle(Request $request) { $signature = $request->header('X-Hub-Signature-256'); #6A9955">// Verify the signature against your secret stored in .env if (!$this->isValidSignature($request->getContent(), $signature)) { throw new AccessDeniedHttpException('Invalid signature'); } #6A9955">// Dispatch to a queue immediately ProcessGitHubWebhook::dispatch($request->all()); return response()->json(['status' => 'accepted'], 202); } private function isValidSignature($payload, $signature): bool { $computed = hash_hmac('sha256', $payload, config('services.github.webhook_secret')); return hash_equals('sha256=' . $computed, $signature); } }
Webhooks often have strict timeout requirements. If the service sends a request and you take 5 seconds to process it, the service might mark the delivery as "failed" and try to retry, leading to duplicate events.
By pushing the payload to a queue, you return a 202 Accepted status code immediately, keeping the sender happy. Learn more about the mechanics of this in Asynchronous Processing with Queues in Laravel.
php artisan make:job ProcessExternalEvent.handle method in your controller to dispatch this job.ProcessExternalEvent job uses the ShouldQueue interface.routes/web.php, Laravel will attempt to verify a CSRF token and fail. Always use routes/api.php or explicitly exclude the route in App\Http\Middleware\VerifyCsrfToken.config/services.php and load it via env(), ensuring you are handling secrets securely to prevent accidental credential leakage.Webhooks are essential for modern integrations. By verifying HMAC signatures, you ensure the integrity of incoming data. By leveraging queues, you ensure your application remains performant and resilient to external traffic spikes. Always treat the payload as untrusted input and implement idempotency checks to prevent duplicate processing.
Up next: We will explore Job Chaining and Batching to handle complex workflows triggered by these incoming webhooks.
Learn to build production-ready integrations by validating webhook signatures and offloading processing to queues to ensure security and system reliability.
Read moreMaster stateless API authentication in Laravel. Learn to issue and verify JWTs, implement secure token rotation, and handle revocation in a high-traffic system.
Handling Webhooks