web-token/jwt-core
Core JWT component from the web-token JWT Framework. Provides foundational building blocks for JSON Web Tokens used by the framework. Read-only split package; development and issues belong in the main jwt-framework repository. Official docs available online.
Installation:
composer require web-token/jwt-core
(Note: This package is read-only and intended for use within the JWT Framework. For Laravel integration, pair with firebase/php-jwt or spomky-labs/base64url for broader compatibility.)
First Use Case: Token Verification
use WebToken\JWT;
use WebToken\JWT\Signature\HS256;
$jwt = new JWT();
$signature = new HS256(config('jwt.secret'));
$decoded = $jwt->decode('your.jwt.token.here', [$signature]);
// Access payload
$payload = $decoded->getPayload();
Where to Look First:
JWT class and algorithm implementations).src/WebToken/JWT/ (core logic for encoding/decoding).Illuminate\Auth\Guard).Create a reusable middleware to validate JWTs on protected routes:
// app/Http/Middleware/AuthenticateJWT.php
namespace App\Http\Middleware;
use Closure;
use WebToken\JWT;
use WebToken\JWT\Signature\HS256;
use WebToken\JWT\Validation\Validation;
class AuthenticateJWT {
public function handle($request, Closure $next) {
$token = $request->bearerToken();
if (!$token) {
return response()->json(['error' => 'Token not provided'], 401);
}
$jwt = new JWT();
$signature = new HS256(config('jwt.secret'));
$validation = new Validation();
try {
$decoded = $jwt->decode($token, [$signature]);
$validation->validate($decoded);
$request->merge(['user' => $decoded->getPayload()]);
return $next($request);
} catch (\Exception $e) {
return response()->json(['error' => 'Invalid token'], 403);
}
}
}
Register in app/Http/Kernel.php:
protected $routeMiddleware = [
'jwt.auth' => \App\Http\Middleware\AuthenticateJWT::class,
];
Generate JWTs for login/logout flows:
use WebToken\JWT\Encoding\JWSEncoding;
use WebToken\JWT\Signature\Algorithm\HS256;
public function login(Request $request) {
$credentials = $request->validate(['email' => 'required', 'password' => 'required']);
$user = User::where('email', $credentials['email'])->first();
if (!$user || !Hash::check($credentials['password'], $user->password)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$payload = [
'sub' => $user->id,
'iat' => time(),
'exp' => time() + 3600,
'roles' => $user->roles
];
$jwt = JWSEncoding::encode(
$payload,
new HS256(config('jwt.secret')),
config('jwt.secret')
);
return response()->json(['token' => $jwt]);
}
Support multiple algorithms (e.g., HS256 for APIs, RS256 for public clients):
$algorithms = [
new HS256(config('jwt.secret')),
new RS256(config('jwt.public_key'), config('jwt.private_key'))
];
$jwt->decode($token, $algorithms);
Extend payloads with Laravel-specific data:
$payload = [
'user_id' => $user->id,
'permissions' => $user->permissions->toArray(),
'aud' => ['api', 'mobile'], // Audiences
'custom_metadata' => ['department' => 'engineering']
];
Create a custom guard for JWT-based authentication:
// app/Providers/AuthServiceProvider.php
protected function jwtGuard() {
return new class extends Guard {
public function user() {
if (!$this->user) {
$token = request()->bearerToken();
if ($token) {
try {
$decoded = $this->jwt->decode($token, [$this->signature]);
$this->user = User::find($decoded->getPayload()['sub']);
} catch (\Exception $e) {
$this->user = null;
}
}
}
return $this->user;
}
};
}
Use PEST/PHPUnit to test token generation/validation:
// tests/Feature/JWTTest.php
public function test_jwt_generation_and_validation() {
$payload = ['user_id' => 1];
$token = JWSEncoding::encode($payload, new HS256('secret'), 'secret');
$decoded = JWSEncoding::decode($token, new HS256('secret'));
expect($decoded->getPayload())->toEqual($payload);
}
Algorithm Mismatches:
HS256 using RS256 will fail silently or throw an exception.alg claim) and match it with the signature class:
$alg = $decoded->getHeader('alg');
if ($alg !== 'HS256') {
throw new \Exception('Algorithm mismatch');
}
Key Management:
config with environment variables:
JWT_SECRET=your-256-bit-secret
JWT_PUBLIC_KEY=-----BEGIN PUBLIC KEY-----
JWT_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----
Encrypter.Token Expiration:
exp claim) by default.$now = time();
$exp = $decoded->getPayload()['exp'];
if ($exp < $now) {
throw new \Exception('Token expired');
}
Payload Size Limits:
user_id) and fetch the rest from the database.Asymmetric Crypto Performance:
RS256/ES256 are CPU-intensive and can bottleneck APIs under high load.HS256 for internal APIs.No Built-in Revocation:
PHP Version Quirks:
Decode Raw JWTs: Use jwt.io to manually decode tokens and inspect headers/payloads.
Enable Detailed Errors: Catch exceptions and log them for debugging:
try {
$decoded = $jwt->decode($token, [$signature]);
} catch (\WebToken\JWT\Exception\InvalidToken $e) {
\Log::error('JWT Error: ' . $e->getMessage());
return response()->json(['error' => 'Invalid token'], 401);
}
Validate Headers:
Ensure the typ (type) header is set to JWT:
$headers = $decoded->getHeader();
if (!isset($headers['typ']) || $headers['
How can I help you explore Laravel packages today?