Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jwt Request Signer Laravel Package

arthem/jwt-request-signer

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. 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).
  2. First Use Case:

    • Sign a URL (e.g., for protected assets like images):
      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();
      
    • Use the signed URL in HTML, APIs, or redirects:
      <img src="https://example.com/protected-image.jpg?token=..." alt="Protected">
      
  3. Validate Incoming Requests:

    • Add middleware or logic to verify signed requests (e.g., in a controller):
      try {
          $signer->validateSignedRequest($request);
          // Proceed if valid.
      } catch (\Arthem\JWTRequestSigner\Exception\InvalidTokenException $e) {
          abort(403, 'Access denied');
      }
      
  4. Configuration:

    • Store the signing key in .env (e.g., JWT_SIGNING_KEY=your-256-bit-secret).
    • Reuse the $signer instance across your app (e.g., bind to Laravel’s service container).

Implementation Patterns

Workflows

  1. Signing Resources:

    • Dynamic URLs: Sign URLs generated on-the-fly (e.g., in API responses or email templates).
      $signedUrl = route('protected.resource', ['id' => 123]) . '?' . http_build_query([
          'token' => $signer->signRequest(new Psr7\Request('GET', route('protected.resource', ['id' => 123])))->getQueryParams()
      ]);
      
    • Batch Signing: Pre-sign multiple URLs for bulk operations (e.g., sending to users via email).
  2. Validation:

    • Middleware: Create Laravel middleware to validate signed requests globally:
      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');
      
  3. Integration with Laravel:

    • Service Provider: Bind the signer to the container for dependency injection:
      $this->app->singleton(JWTRequestSigner::class, function ($app) {
          return new JWTRequestSigner(
              config('jwt.signing_key'),
              config('jwt.ttl'),
              config('jwt.query_param')
          );
      });
      
    • Config File: Add to 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'),
      ];
      
  4. Customizing Tokens:

    • Add Metadata: Extend the JWT payload by overriding the signRequest method or using a custom class:
      $signer->signRequest($request, ['user_id' => auth()->id()]);
      
    • Token Claims: Access claims during validation (if extended):
      $claims = $signer->getClaimsFromRequest($request);
      

Best Practices

  • Key Management: Use Laravel’s env() or a secure secrets manager (e.g., AWS Secrets Manager).
  • TTL: Set appropriate expiration times (e.g., short for public links, longer for user-specific resources).
  • HTTPS: Always use HTTPS to prevent token interception.
  • Logging: Log validation failures for security audits.

Gotchas and Tips

Pitfalls

  1. Key Rotation:

    • If the signing key changes, all existing tokens become invalid. Plan for key rotation during maintenance windows.
    • Workaround: Use a short TTL (e.g., 15–30 minutes) for public-facing URLs.
  2. Token Leakage:

    • Signed URLs may leak in browser history, logs, or referrer headers. Avoid using for sensitive actions (e.g., password resets).
    • Tip: Use POST requests with hidden token fields for sensitive operations.
  3. PSR-7 Compatibility:

    • The package requires PSR-7 requests. Laravel’s Illuminate\Http\Request is not PSR-7 compliant by default.
    • Fix: Convert Laravel requests to PSR-7:
      use Nyholm\Psr7\Factory\Psr17Factory;
      $psr7Factory = new Psr17Factory();
      $psr7Request = $psr7Factory->createRequest(
          $request->method(),
          $request->getRequestUri()
      )->withHeaders($request->header());
      $signer->validateSignedRequest($psr7Request);
      
  4. Query String Handling:

    • The package appends the token to the query string. If the original URL already has query params, they may be overwritten or malformed.
    • Tip: Manually construct the URI to preserve existing params:
      $uri = $request->getUri();
      $query = $uri->getQuery();
      parse_str($query, $queryParams);
      $queryParams['token'] = $token;
      $signedUri = $uri->withQuery(http_build_query($queryParams));
      
  5. Clock Skew:

    • Tokens expire based on the server’s clock. If servers are out of sync (e.g., across data centers), tokens may fail prematurely.
    • Tip: Use a time synchronization service (e.g., NTP) or add a small buffer (e.g., ttl + 60).
  6. No Built-in Rate Limiting:

    • The package doesn’t protect against brute-force attacks on the token. Combine with Laravel’s throttle middleware if needed.

Debugging

  1. Invalid Token Errors:

    • Check the token payload (decode it with firebase/php-jwt or jwt.io) to verify claims.
    • Common causes:
      • Expired token (exp claim).
      • Mismatched signing key.
      • Tampered query string.
  2. Logging:

    • Enable debug mode in the JWT library (if used) to log token validation:
      $signer = new JWTRequestSigner(..., ..., ..., [
          'debug' => true,
      ]);
      
  3. Testing:

    • Mock the signer in tests to avoid key exposure:
      $mockSigner = $this->createMock(JWTRequestSigner::class);
      $mockSigner->method('validateSignedRequest')->willReturn(true);
      $this->app->instance(JWTRequestSigner::class, $mockSigner);
      

Extension Points

  1. Custom Claims:

    • Extend the signRequest method to include additional data:
      $signedRequest = $signer->signRequest($request, [
          'user_id' => auth()->id(),
          'ip' => request()->ip(),
      ]);
      
  2. Token Storage:

    • Store tokens in a database for revocation (e.g., if a user revokes access to a resource). Compare tokens against a blacklist during validation.
  3. Algorithm Support:

    • The package defaults to HS256. For stronger security, extend to support RS256 (asymmetric keys) by overriding the sign and verify methods.
  4. Framework-Specific Helpers:

    • Create helper methods for common Laravel use cases:
      // app/Helpers/JWTHelper.php
      use Arthem\JWTRequestSigner\JWTRequestSigner;
      
      class JWTHelper
      {
          public static function signUrl(string $url, int $tt
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours