If you've worked with APIs, authentication, or third-party integrations, you've almost certainly run into JWTs (JSON Web Tokens).
JWT (pronounced: JOT) is a compact string used to pass data between systems. It has three base64url-encoded parts separated by dots: header, payload, and signature. The header defines metadata like the algorithm, the payload contains claims such as user id and expiration, and the signature ensures integrity. The header and payload can be decoded into JSON for quick inspection.
Let's create a simple trait you can use on any class in your Laravel application to read the contents of a JWT:
<?php
namespace Quartzy\Illuminate\Support\Traits;
use Illuminate\Support\Str;
trait InspectsJwt
{
public function inspectJwt(string $jwt): array
{
if (!str_contains($jwt, '.')) {
return [];
}
return collect(explode('.', $jwt))
->map(function (string $segment) {
$decoded = base64_decode(
Str::of($segment)
->replace('_', '/')
->replace('-', '+')
->__toString()
);
return json_decode($decoded, true) ?? [];
})
->filter() // removes empty payload elements from the array
->reduce(fn (array $carry, array $item) => array_merge($carry, $item), []);
}
}
Now you can inspect the contents of JWT with ease! Let's look at an example where a user is making a request to our app and their JWT token is passed as a header in the request. This would be our example JWT:
(You can copy the following JWT and examine it on JWT.io
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2Nzg5MCIsInV1aWQiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJuYW1lIjoiTWFyayBUb3duc2VuZCIsImVtYWlsIjoibWFyay50b3duc2VuZEBleGFtcGxlLmNvbSIsInJvbGUiOiJkZXZlbG9wZXIiLCJpYXQiOjE3MTAwMDAwMDAsImV4cCI6MTcxMDAwMzYwMH0.signatureplaceholder
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Quartzy\Illuminate\Support\Traits\InspectsJwt;
use App\Models\User;
use Illuminate\Support\Facades\Log;
class AuthenticateWithJwtUuid
{
use InspectsJwt;
public function handle(Request $request, Closure $next)
{
$authorization = $request->header('Authorization', '');
if (str_starts_with($authorization, 'Bearer ')) {
$jwt = substr($authorization, 7);
$payload = $this->inspectJwt($jwt);
if (!empty($payload['uuid'])) {
// Pull user by UUID instead of numeric ID
$user = User::where('uuid', $payload['uuid'])->first();
if ($user) {
$request->attributes->set('user', $user);
Log::info("JWT authenticated user {$user->name} with role {$payload['role']}");
}
}
}
return $next($request);
}
}
That's all there is to it! Hopefully this helps demystify JWTs and simplifies working with them in your application!
Top comments (1)
While I do think it is a great post. I don't understand the need of using
CollectionenStr.The body of
inspectJWTcan be written as:I see the beauty of temporary variables as extra information about what each step does.
There is no mapping and then reducing. Just one loop and done.
Also the
Strbuilder pattern is much too verbose.Don't just use every part of Laravel, use them when they are a better solution than using PHP.