Installation:
composer require arthem/jwt-request-signer nyholm/psr7
arthem/jwt-request-signer: Core package.nyholm/psr7: PSR-7 HTTP message implementation (required for compatibility).First Use Case:
use Arthem\JWTRequestSigner\JWTRequestSigner;
use Nyholm\Psr7\Psr7;
$signer = new JWTRequestSigner(
'your-secret-key-here', // Replace with a strong key (e.g., from `.env`)
3600, // Token expires in 1 hour (seconds)
'token' // Custom query param name (default: 'x-token')
);
$request = new Psr7\Request('GET', 'https://example.com/protected-image.jpg');
$signedUri = (string) $signer->signRequest($request)->getUri();
<img src="https://example.com/protected-image.jpg?token=..." alt="Protected">
Validate Incoming Requests:
try {
$signer->validateSignedRequest($request);
// Proceed if valid.
} catch (\Arthem\JWTRequestSigner\Exception\InvalidTokenException $e) {
abort(403, 'Access denied');
}
Configuration:
.env (e.g., JWT_SIGNING_KEY=your-256-bit-secret).$signer instance across your app (e.g., bind to Laravel’s service container).Signing Resources:
$signedUrl = route('protected.resource', ['id' => 123]) . '?' . http_build_query([
'token' => $signer->signRequest(new Psr7\Request('GET', route('protected.resource', ['id' => 123])))->getQueryParams()
]);
Validation:
namespace App\Http\Middleware;
use Arthem\JWTRequestSigner\JWTRequestSigner;
use Closure;
class ValidateSignedRequest
{
protected $signer;
public function __construct(JWTRequestSigner $signer)
{
$this->signer = $signer;
}
public function handle($request, Closure $next)
{
$this->signer->validateSignedRequest($request);
return $next($request);
}
}
Register in app/Http/Kernel.php:
protected $routeMiddleware = [
'signed' => \App\Http\Middleware\ValidateSignedRequest::class,
];
Use in routes:
Route::get('/protected', function () { ... })->middleware('signed');
Integration with Laravel:
$this->app->singleton(JWTRequestSigner::class, function ($app) {
return new JWTRequestSigner(
config('jwt.signing_key'),
config('jwt.ttl'),
config('jwt.query_param')
);
});
config/jwt.php:
return [
'signing_key' => env('JWT_SIGNING_KEY'),
'ttl' => env('JWT_TTL', 3600), // Default: 1 hour
'query_param' => env('JWT_QUERY_PARAM', 'x-token'),
];
Customizing Tokens:
signRequest method or using a custom class:
$signer->signRequest($request, ['user_id' => auth()->id()]);
$claims = $signer->getClaimsFromRequest($request);
env() or a secure secrets manager (e.g., AWS Secrets Manager).Key Rotation:
Token Leakage:
PSR-7 Compatibility:
Illuminate\Http\Request is not PSR-7 compliant by default.use Nyholm\Psr7\Factory\Psr17Factory;
$psr7Factory = new Psr17Factory();
$psr7Request = $psr7Factory->createRequest(
$request->method(),
$request->getRequestUri()
)->withHeaders($request->header());
$signer->validateSignedRequest($psr7Request);
Query String Handling:
$uri = $request->getUri();
$query = $uri->getQuery();
parse_str($query, $queryParams);
$queryParams['token'] = $token;
$signedUri = $uri->withQuery(http_build_query($queryParams));
Clock Skew:
ttl + 60).No Built-in Rate Limiting:
throttle middleware if needed.Invalid Token Errors:
firebase/php-jwt or jwt.io) to verify claims.exp claim).Logging:
$signer = new JWTRequestSigner(..., ..., ..., [
'debug' => true,
]);
Testing:
$mockSigner = $this->createMock(JWTRequestSigner::class);
$mockSigner->method('validateSignedRequest')->willReturn(true);
$this->app->instance(JWTRequestSigner::class, $mockSigner);
Custom Claims:
signRequest method to include additional data:
$signedRequest = $signer->signRequest($request, [
'user_id' => auth()->id(),
'ip' => request()->ip(),
]);
Token Storage:
Algorithm Support:
sign and verify methods.Framework-Specific Helpers:
// app/Helpers/JWTHelper.php
use Arthem\JWTRequestSigner\JWTRequestSigner;
class JWTHelper
{
public static function signUrl(string $url, int $tt
How can I help you explore Laravel packages today?