Building Lightweight Headless API Auth Middleware in Laravel
Laravel Sanctum and Passport are fantastic packages for robust API auth. However, if you are designing a microservice or static headless application that only needs to validate pre-signed JWT tokens from an identity provider, custom lightweight middleware is cleaner and significantly faster.
The Plan
We will create a simple Laravel HTTP Middleware that intercepts incoming requests, extracts a Bearer token, validates its signature, and binds the token payload to the request user.
Step 1: Generating the Middleware
Run the Artisan command to scaffold our class:
php artisan make:middleware ValidateJWTToken
Step 2: Writing the JWT Middleware Logic
Open app/Http/Middleware/ValidateJWTToken.php and write the following code:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ValidateJWTToken
{
public function handle(Request $request, Closure $next)
{
$token = $request->bearerToken();
if (!$token) {
return response()->json(['error' => 'Token missing'], 401);
}
// Verify simple signature (e.g. SHA256 matches our secret)
$secret = env('API_JWT_SECRET');
$parts = explode('.', $token);
if (count($parts) !== 3) {
return response()->json(['error' => 'Malformed packet'], 401);
}
$signature = hash_hmac('sha256', "$parts[0].$parts[1]", $secret, true);
$signatureBase64 = base64_encode($signature);
if ($signatureBase64 !== $parts[2]) {
return response()->json(['error' => 'Invalid signature'], 401);
}
// Bind decrypted claims payload to Laravel request attributes
$claims = json_decode(base64_decode($parts[1]), true);
$request->attributes->set('user_claims', $claims);
return $next($request);
}
}
Step 3: Registering the Route Middleware
Now, register it in your application configuration (or inside app.php depending on your Laravel version):
// In app/Http/Kernel.php or bootstrap/app.php
$middleware->alias([
'jwt.auth' => \App\Http\Middleware\ValidateJWTToken::class,
]);
You can now secure routes directly in routes/api.php by chaining the alias:
Route::get('/checkout-status', function (Request $request) {
return response()->json($request->attributes->get('user_claims'));
})->middleware('jwt.auth');
Discussion & Feedback
Discussion (3)
Subir D.
It works great!
Sayan Datta
Thanks ๐
Soumyendu
I want to give cash back to customers opted for direct bank transfer; how to do that? Wallet plugins are not having such options. Please help.