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

Url Signature Bundle Laravel Package

dsentker/url-signature-bundle

Symfony 4+ bundle for dsentker/url-signature. Generate signed (optionally expiring) URLs in Twig or controllers, validate signatures via DI/helper trait or annotations, and protect query/route parameters from tampering.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:

    composer require dsentker/url-signature-bundle
    

    For Symfony Flex, no additional steps are required. For manual setup, add to config/bundles.php:

    Shift\UrlSignatureBundle\ShiftUrlSignatureBundle::class => ['all' => true],
    
  2. Generate a signed URL in Twig:

    <a href="{{ signed_url('route_name', { param: value }) }}">Secure Link</a>
    

    This appends a cryptographic hash to the URL query string.

  3. Verify the signature in a controller:

    use Shift\UrlSignatureBundle\Utils\RequestValidator;
    
    public function secureAction(RequestValidator $validator) {
        if (!$validator->isValid()) {
            throw new \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException();
        }
        // Proceed if valid
    }
    

First Use Case: Secure API Endpoints

  • Problem: Protect API endpoints from tampering (e.g., modifying query parameters).
  • Solution:
    • Generate signed URLs in your frontend/backend:
      $builder->signUrlFromPath('api.payment', ['amount' => 100], '+1 hour');
      
    • Validate in the controller using the RequestValidator trait or annotation.

Implementation Patterns

1. Twig Integration (Frontend)

  • Replace path() with signed_url() in templates:
    {{ signed_url('download_file', { id: file.id }, '+5 minutes') }}
    
  • Workflow:
    1. Pass route name, parameters, and optional expiry (e.g., '+10 minutes').
    2. Bundle auto-generates a hash (e.g., ?id=123&_hash=abc123).
    3. Hash is validated server-side.

2. Controller Workflows

  • Signing URLs:

    $builder->signUrl('https://example.com/pay', '+1 hour'); // Absolute URL
    $builder->signUrlFromPath('route.name', ['param' => 'value']); // Route-based
    
  • Validation:

    • Dependency Injection (Recommended):
      public function action(RequestValidator $validator) {
          $validator->verify(); // Throws exception if invalid
      }
      
    • Annotation (Global):
      /**
       * @RequiresSignatureVerification()
       */
      public function action() { ... }
      
      Note: Useful for protecting entire routes without manual checks.
  • Trait-Based (Legacy Controllers):

    use Shift\UrlSignatureBundle\Controller\UrlSignatureTrait;
    
    class OldController {
        use UrlSignatureTrait;
    
        public function action() {
            $this->getValidator()->verify();
        }
    }
    

3. Expiry Handling

  • Support for relative ('+10 minutes'), absolute (\DateTime), or timestamp (1634567890) expiry.
  • Example:
    {{ signed_url('route', { id: 1 }, new \DateTime('+1 day')) }}
    

4. Custom Configuration

  • Override defaults in config/services.yaml:
    parameters:
        shift_url_signature.hash_algo: 'sha256'  # Default: APP_SECRET
        shift_url_signature.query_signature_name: '_sig'  # Custom hash key
    
  • Advanced: Extend UrlSignature\HashConfiguration for bitmask flags (e.g., exclude PATH from hashing).

5. Integration with Laravel

  • Symfony Bridge: Use symfony/http-foundation or symfony/routing in Laravel:
    composer require symfony/http-foundation symfony/routing
    
  • Service Provider: Register the bundle in config/app.php:
    'providers' => [
        Shift\UrlSignatureBundle\ShiftUrlSignatureBundle::class,
    ],
    
  • Twig: Ensure Twig is configured to use Symfony’s SignedPathExtension.

Gotchas and Tips

Pitfalls

  1. Trait Constructor Conflicts:

    • Avoid using UrlSignatureTrait if your controller has a constructor (PHP trait constructor limitations).
    • Workaround: Use DI (UrlSignatureBuilder/RequestValidator) instead.
  2. Expiry Precision:

    • Relative strings (e.g., '+1 hour') use PHP’s date() parsing. Test edge cases like '+1 day 2 hours'.
    • Tip: Use \DateTime for complex expiry logic.
  3. Hash Collisions:

    • Default MD5 is fast but collision-prone. Upgrade to sha256 in services.yaml:
      shift_url_signature.hash_algo: 'sha256'
      
  4. Query Parameter Ordering:

    • The hash depends on the order of query parameters. Ensure consistency:
      { id: 1, sort: 'asc' }  # Hash will differ from { sort: 'asc', id: 1 }
      
    • Tip: Normalize parameters in your Twig templates or controllers.
  5. Annotation Performance:

    • @RequiresSignatureVerification runs before the controller action. Avoid heavy logic in annotated routes.
    • Tip: Use for simple redirects or lightweight validations.
  6. Secret Management:

    • Defaults to APP_SECRET. For production:
      • Store secrets in environment variables (e.g., .env):
        SHIFT_URL_SIGNATURE_SECRET=your_secure_key_here
        
      • Override in services.yaml:
        parameters:
            shift_url_signature.secret: '%env(SHIFT_URL_SIGNATURE_SECRET)%'
        

Debugging Tips

  1. Log Invalid Requests:

    try {
        $validator->verify();
    } catch (\Exception $e) {
        \Log::error('Invalid signature', ['url' => $request->getUri()]);
        throw $e;
    }
    
  2. Manual Hash Verification:

    • Recreate the hash manually to debug:
      use UrlSignature\HashConfiguration;
      $config = new HashConfiguration('APP_SECRET');
      $config->setAlgorithm('sha256');
      $hash = $config->generateHash('https://example.com?param=value');
      
  3. Disable Validation Temporarily:

    • For testing, override the validator:
      $validator->setEnabled(false); // If supported in your version
      

Extension Points

  1. Custom Hash Algorithms:

    • Extend UrlSignature\HashConfiguration to support algorithms like argon2 or blake3.
  2. Additional Query Parameters:

    • Whitelist/blacklist parameters in the hash:
      # services.yaml
      shift_url_signature.configuration.default:
          calls:
              - method: setHashMask
                arguments: [0b00001]  # Only hash the scheme (adjust bitmask)
      
  3. Laravel-Specific Extensions:

    • Create a facade for UrlSignatureBuilder:
      facade(UrlSignatureBuilder::class, 'UrlSignature');
      
    • Publish config for customization:
      php artisan vendor:publish --provider="Shift\UrlSignatureBundle\ShiftUrlSignatureBundle"
      

Performance Considerations

  • Hashing Overhead: SHA-256 adds ~1-2ms per request. Benchmark in high-traffic routes.
  • Caching: Cache signed URLs if expiry is long (e.g., pre-signed download links).
  • Batch Validation: For APIs, validate signatures in middleware to avoid per-request overhead.

Security Quirks

  • Hash Leakage: Ensure _hash query parameters are not logged in server logs or browser dev tools.
  • Expiry Handling: Test expiry edge cases (e.g., clock skew, DST transitions).
  • CSRF Protection: Combine with Symfony’s csrf_token for forms to defend against both URL tampering and CSRF.
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.
bugban/symfony
beyonder-capi/workflow-extensions-bundle
beyonder-capi/job-queue-bundle
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin