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

Request Signer Bundle Laravel Package

arthem/request-signer-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require arthem/request-signer-bundle
    

    For JWT or AWS S3 support, install the required adapters:

    composer require arthem/jwt-request-signer aws/aws-sdk-php
    
  2. Configure the bundle in config/packages/arthem_request_signer.yaml:

    arthem_request_signer:
      signers:
        my_jwt_signer:
          jwt:
            ttl: 3600
            signing_key: '%env(resolve:MY_SIGNING_KEY)%'
    
  3. Define environment variables in .env:

    MY_SIGNING_KEY=your_secure_key_here
    
  4. First use case: Sign a URL in a controller or normalizer:

    use Arthem\RequestSignerBundle\RequestSigner;
    
    public function generateSignedUrl(RequestSigner $signer): string
    {
        return $signer->signUri(
            'https://example.com/asset.jpg',
            $request,
            ['signer' => 'my_jwt_signer']
        );
    }
    

Implementation Patterns

Common Workflows

1. Signing URLs for Protected Resources

  • Use in serializers/normalizers to generate signed URLs for API responses (e.g., file downloads, pre-signed S3 URLs).
  • Example:
    $signedUrl = $signer->signUri(
        $this->urlGenerator->generate('asset_download', ['id' => $assetId]),
        $request,
        ['signer' => 'aws_images', 'ResponseContentDisposition' => 'attachment']
    );
    

2. Validating Incoming Requests

  • Validate signed requests in controllers/middleware to ensure integrity.
  • Example:
    public function secureAction(Request $request, RequestSigner $signer)
    {
        try {
            $signer->validateRequest($request);
            // Proceed if valid
        } catch (InvalidSignatureException $e) {
            throw new AccessDeniedHttpException();
        }
    }
    

3. Dynamic Signer Selection

  • Override the default signer per request using the signer option:
    $signer->signUri($url, $request, ['signer' => 'my_jwt_signer']);
    

4. Integration with Symfony Components

  • Event Listeners: Validate requests during kernel events (e.g., kernel.request).
  • Twig: Pass signed URLs to templates:
    <a href="{{ signedUrl('asset_download', asset.id) }}">Download</a>
    
    (Requires a Twig extension or helper.)

5. AWS S3-Specific Patterns

  • Use ResponseContentDisposition to force downloads:
    $signer->signUri($url, $request, ['ResponseContentDisposition' => 'attachment']);
    
  • Leverage S3’s pre-signed URLs for temporary access without server-side validation.

Integration Tips

With API Platform

  • Override serialize() in entity normalizers to inject signed URLs:
    public function serialize($object, $format, array $context)
    {
        $data = parent::serialize($object, $format, $context);
        $data['downloadUrl'] = $this->signer->signUri(
            $this->urlGenerator->generate('api_asset_download', ['id' => $object->getId()])
        );
        return $data;
    }
    

With Middleware

  • Validate all incoming requests globally:
    public function __invoke(Request $request, RequestSigner $signer)
    {
        $signer->validateRequest($request);
        return $next($request);
    }
    
    Register in config/routes/protected.yaml:
    _protected:
        path: /
        controller: App\Middleware\ValidateSignedRequestMiddleware
    

With Guzzle HTTP Client

  • Sign URLs dynamically before making requests:
    $client = new Client();
    $signedUrl = $signer->signUri('https://api.example.com/data');
    $response = $client->get($signedUrl);
    

Gotchas and Tips

Pitfalls

1. Clock Skew with JWT

  • If using JWT, ensure the server and client clocks are synchronized (within ttl seconds). Use NTP or a time-sync service.
  • Fix: Set a conservative ttl (e.g., 300 seconds) or implement clock drift handling.

2. AWS S3 Credential Leaks

  • Hardcoding AWS credentials in config is unsafe. Always use %env() and restrict IAM permissions.
  • Fix: Use IAM roles or temporary credentials (e.g., AWS STS).

3. Missing Request Validation

  • Forgetting to validate signed requests can expose endpoints to tampering.
  • Fix: Always call $signer->validateRequest($request) in controllers/middleware.

4. URL Encoding Issues

  • Signed URLs may break if not properly encoded. The bundle handles this, but custom logic (e.g., query params) might fail.
  • Fix: Use UrlGeneratorInterface::ABSOLUTE_URL and let the bundle handle encoding.

5. Deprecated Adapters

  • The package is unmaintained (last release: 2020). AWS SDK v3 may not work out-of-the-box.
  • Fix: Fork the package or use alternatives like league/url-signatures.

Debugging

Invalid Signature Errors

  • Check:
    1. Signing Key: Ensure %env(resolve:MY_SIGNING_KEY)% matches the key used to sign the URL.
    2. Request Method: The bundle signs based on the HTTP method (e.g., GET). Mismatches cause failures.
    3. Query Parameters: All params used for signing must match exactly (order-sensitive).
  • Debug Tip: Log the signed URL and compare it manually:
    error_log($signer->signUri($url, $request));
    

AWS S3-Specific Issues

  • 403 Forbidden: Verify:
    • Bucket name is correct.
    • IAM user has s3:GetObject permissions.
    • Region matches the bucket’s region.
  • Debug Tip: Test with the AWS CLI first:
    aws s3 presign s3://my_bucket/file.jpg --expires-in 3600
    

Configuration Quirks

Default Signer

  • If no signer is specified in signUri(), the bundle uses the first configured signer (alphabetical order).
  • Fix: Explicitly set the signer name to avoid ambiguity.

TTL Units

  • ttl in the config is in seconds, not minutes/hours.
  • Fix: Use 3600 for 1 hour, not 60.

Environment Variables

  • Use %env(resolve:VAR)% to resolve nested env vars (e.g., MY_SIGNING_KEY from .env.local).
  • Fix: Ensure .env.local is loaded (Symfony’s default behavior).

Extension Points

Custom Signer Adapters

  • Extend the bundle by implementing Arthem\RequestSignerBundle\Signer\SignerInterface:
    class CustomSigner implements SignerInterface
    {
        public function sign(string $uri, Request $request, array $options): string
        {
            // Custom logic
        }
    
        public function validate(string $uri, Request $request, array $options): bool
        {
            // Custom validation
        }
    }
    
  • Register in config/packages/arthem_request_signer.yaml:
    services:
        app.custom_signer:
            class: App\Signer\CustomSigner
            tags: ['arthem_request_signer.signer']
    
    arthem_request_signer:
        signers:
            custom_signer: ~
    

Event Dispatching

  • Listen for signing/validation events (if the bundle supports them) to log or modify behavior:
    // Hypothetical event (check bundle source for actual events)
    $eventDispatcher->addListener(
        RequestSignerEvents::SIGNING,
        function (SigningEvent $event) {
            // Modify $event->getOptions() or $event->setUri()
        }
    );
    

Caching Signed URLs

  • For performance, cache signed URLs (e.g., with Symfony Cache component):
    $cacheKey = md5($url . $request->getClientIp());
    $signedUrl = $cache->get($cacheKey, function() use ($signer, $url, $request) {
        return $signer->signUri($url, $request);
    });
    
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.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
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