Reading HTTP request headers in Laravel — for a custom API key, checking the content type, or reading a client-provided token — goes through the Request object's header() method and a couple of related convenience checks.
Getting a specific header
$apiKey = $request->header('X-Api-Key');
Getting a header with a default fallback value
$locale = $request->header('Accept-Language', 'en');
Header names are matched case-insensitively
$request->header('Content-Type');
$request->header('content-type'); // returns the exact same value
HTTP headers are case-insensitive by specification — Laravel's header() method reflects this correctly, so it doesn't matter whether the header is checked using its conventional capitalization or an all-lowercase (or any other casing) version of the same name.
Getting every header at once
$allHeaders = $request->headers->all();
This returns an array of every header sent with the request — genuinely useful for debugging exactly what a client actually sent, though $allHeaders' values are each returned as an array (since a header can technically repeat with multiple values), not a plain string, unlike the single-header header() method.
Checking if a header exists at all
if ($request->hasHeader('X-Api-Key')) {
// header was present
}
Reading the Bearer token from an Authorization header
$token = $request->bearerToken();
bearerToken() is a dedicated convenience method that specifically parses an Authorization: Bearer {token} header and returns just the token portion — simpler and less error-prone than manually reading the raw Authorization header and stripping the "Bearer " prefix with string manipulation.
Checking the request's expected content type
if ($request->expectsJson()) {
return response()->json(['error' => 'Not found'], 404);
}
return response()->view('errors.404', [], 404);
expectsJson() checks the Accept header (along with whether the request is AJAX) to determine if the client wants a JSON response rather than an HTML page — genuinely useful for one route or error handler that needs to correctly serve both a browser-based frontend and a JSON API consumer.
Setting a custom header on the outgoing response
return response('Hello')->header('X-Custom-Header', 'some-value');
// Setting multiple headers at once
return response('Hello')->withHeaders([
'X-Custom-Header' => 'some-value',
'X-Another-Header' => 'another-value',
]);
A common real use case: validating a webhook's signature header
public function handleWebhook(Request $request)
{
$signature = $request->header('X-Webhook-Signature');
$expected = hash_hmac('sha256', $request->getContent(), config('services.webhook.secret'));
if (! hash_equals($expected, $signature)) {
abort(403, 'Invalid webhook signature.');
}
// process the verified webhook
}
hash_equals(), rather than a plain === comparison, is used deliberately here — it performs a timing-safe comparison, which prevents a timing-attack side channel that could otherwise be used to guess the correct signature one character at a time by measuring how long each incorrect guess takes to reject.