Installation
composer require fproject/php-jwt
Add to composer.json if not using autoloading:
"autoload": {
"psr-4": {
"App\\": "app/",
"Firebase\\JWT\\": "vendor/fproject/php-jwt/src/"
}
}
Run composer dump-autoload.
First Use Case: Decoding a JWT
use Firebase\JWT\JWT;
$token = 'your.jwt.token.here';
$decoded = JWT::decode($token, 'secret_key', ['HS256']);
Where to Look First
src/ directory for core classes (JWT.php, Key.php, ExpiredException.php, etc.).Encoding Tokens
$payload = [
'iss' => 'your-app',
'iat' => time(),
'data' => ['user_id' => 123]
];
$token = JWT::encode($payload, 'secret_key', 'HS256');
Decoding with Validation
try {
$decoded = JWT::decode($token, 'secret_key', ['HS256']);
// $decoded is a stdClass; cast to array if needed:
$data = (array) $decoded;
} catch (\Firebase\JWT\ExpiredException $e) {
// Handle expired token
} catch (\Firebase\JWT\SignatureInvalidException $e) {
// Handle invalid signature
}
Using JWK (JSON Web Key) for Asymmetric Signing
$jwk = [
'kty' => 'RSA',
'e' => 'AQAB',
'n' => 'your_modulus_here',
'd' => 'your_private_exponent',
'p' => 'your_first_factor',
'q' => 'your_second_factor',
'dp' => 'your_first_factor_crt',
'dq' => 'your_second_factor_crt',
'qi' => 'your_first_crt_coefficient'
];
$token = JWT::encode($payload, $jwk, 'RS256');
Middleware for Laravel Create a middleware to validate JWTs on protected routes:
namespace App\Http\Middleware;
use Closure;
use Firebase\JWT\JWT;
use Firebase\JWT\ExpiredException;
class AuthenticateJWT
{
public function handle($request, Closure $next)
{
$token = $request->bearerToken();
if (!$token) {
return response()->json(['error' => 'Token not provided'], 401);
}
try {
$decoded = JWT::decode($token, config('jwt.secret'), [config('jwt.algorithm')]);
$request->merge(['user' => (array) $decoded]);
} catch (ExpiredException $e) {
return response()->json(['error' => 'Token expired'], 401);
} catch (\Exception $e) {
return response()->json(['error' => 'Invalid token'], 401);
}
return $next($request);
}
}
Register in app/Http/Kernel.php:
protected $routeMiddleware = [
'jwt.auth' => \App\Http\Middleware\AuthenticateJWT::class,
];
Storing Tokens Securely
Use Laravel's encrypt() for sensitive keys:
$secret = config('jwt.secret');
$encrypted = encrypt($secret); // Store this in DB/env
Algorithm Mismatch
HS256 but decoding with RS256, the signature will fail.Clock Skew in Validation
nbf (not before) or exp (expiry) claims may fail due to server time mismatches.$decoded = JWT::decode($token, 'secret', ['HS256'], true, ['leeway' => 300]);
JWK Key Format
d, p, q for RSA) will cause errors.web-token/jwt-framework for generation.Deprecated Methods
JWT::verify() in favor of JWT::decode() + exception handling (more explicit).No Built-in Refresh Tokens
if ($decoded->refresh_token && $request->input('refresh_token') === $decoded->refresh_token) {
$newToken = JWT::encode($payload, 'secret', 'HS256');
return response()->json(['token' => $newToken]);
}
Decode Without Validation
Use JWT::decode($token, null, ['HS256']) to inspect payloads without signature checks.
Check Token Structure Use jwt.io to validate token claims manually.
Enable Error Logging Wrap decodes in try-catch blocks to log exceptions:
try {
$decoded = JWT::decode($token, 'secret', ['HS256']);
} catch (\Exception $e) {
\Log::error("JWT Decode Error: " . $e->getMessage());
throw $e;
}
Custom Claims Validation Extend the library by adding a validator:
class CustomJWTValidator
{
public static function validate($payload)
{
if (!isset($payload->iss) || $payload->iss !== 'your-app') {
throw new \Exception('Invalid issuer');
}
}
}
Use in middleware:
CustomJWTValidator::validate($decoded);
Key Management For production, integrate with a key management system (e.g., AWS KMS, HashiCorp Vault) to fetch JWKs dynamically.
Performance
Testing
Use JWT::encode() with predictable payloads/secrets for unit tests:
$testToken = JWT::encode(['test' => true], 'secret', 'HS256');
How can I help you explore Laravel packages today?