curentis/cloudfront-signer

A fluent Laravel SDK for generating AWS CloudFront signed URLs and cookies.

Maintainers

Package info

github.com/curentis/cloudfront-signer

pkg:composer/curentis/cloudfront-signer

Statistics

Installs: 647

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.3.1 2026-05-29 05:49 UTC

This package is auto-updated.

Last update: 2026-05-29 05:49:30 UTC


README

Latest Version on Packagist Tests Code Style Static Analysis License

A strictly-typed, modern Laravel package for generating AWS CloudFront signed URLs. Built on PHP 8.2+ with a clean interface-driven design for easy testing and extensibility.

Table of Contents

Requirements

Dependency Version
PHP ^8.2
Laravel ^11.0
AWS SDK ^3.0

Installation

Install via Composer:

composer require curentis/cloudfront-signer

The service provider and facade are auto-discovered via Laravel's package discovery. No manual registration required.

Publish the configuration file:

php artisan vendor:publish --tag="cloudfront-signer-config"

Configuration

Environment Variables

Add the following to your .env file:

CLOUDFRONT_KEY_PAIR_ID=APKA...
CLOUDFRONT_REGION=us-east-1
CLOUDFRONT_DEFAULT_EXPIRATION=3600

# Choose one of the private key options below
CLOUDFRONT_PRIVATE_KEY_PATH=storage/certs/cloudfront.pem
CLOUDFRONT_PRIVATE_KEY_CONTENT=
Variable Required Default Description
CLOUDFRONT_KEY_PAIR_ID Yes Public key ID from CloudFront > Key Management
CLOUDFRONT_REGION No us-east-1 AWS region for the SDK client
CLOUDFRONT_DEFAULT_EXPIRATION No 3600 Default signed URL lifetime in seconds
CLOUDFRONT_PRIVATE_KEY_PATH One of Path to the .pem key file (absolute or relative)
CLOUDFRONT_PRIVATE_KEY_CONTENT One of Raw PEM key string (takes precedence over path)

Note: CLOUDFRONT_KEY_PAIR_ID is the public key ID found in CloudFront > Key Management > Public Keys — this is not your IAM Access Key ID.

Private Key Options

The package supports two ways to provide your CloudFront private key:

Option A — File path (traditional, local environments):

Store the .pem file in a non-public directory such as storage/certs/, then set:

CLOUDFRONT_PRIVATE_KEY_PATH=storage/certs/cloudfront-private-key.pem

Both absolute paths and paths relative to the project root are accepted.

Option B — Inline content (recommended for containers and secret managers):

Provide the raw PEM string directly. For single-line env vars, use escaped newlines:

CLOUDFRONT_PRIVATE_KEY_CONTENT="-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgk...\n-----END PRIVATE KEY-----"

Multi-line format is also accepted if your environment supports it:

CLOUDFRONT_PRIVATE_KEY_CONTENT="-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgk...
-----END PRIVATE KEY-----"

When both options are set, CLOUDFRONT_PRIVATE_KEY_CONTENT takes precedence.

Usage

Facade

The CloudFrontSigner facade is the quickest way to generate a signed URL:

use Curentis\CloudFrontSigner\Facades\CloudFrontSigner;

$url = 'https://cdn.yoursite.com/videos/intro.mp4';

// Use the default expiration defined in config
$signedUrl = CloudFrontSigner::sign($url);

// Custom expiration via Carbon or any DateTimeInterface
$signedUrl = CloudFrontSigner::sign($url, now()->addDays(7));

// Custom expiration via seconds offset
$signedUrl = CloudFrontSigner::sign($url, 86400); // expires in 24 hours

Dependency Injection

Inject the Signer contract directly into your controllers or services. This approach is recommended as it makes the dependency explicit and keeps your code easily testable.

use Curentis\CloudFrontSigner\Contracts\Signer;

class VideoController extends Controller
{
    public function __construct(private readonly Signer $signer) {}

    public function show(string $filename): \Illuminate\View\View
    {
        $signedUrl = $this->signer->sign(
            "https://cdn.example.com/videos/{$filename}",
            now()->addHours(2)
        );

        return view('video.player', compact('signedUrl'));
    }
}

Mocking in tests:

Because the package binds the Signer interface, you can mock it without touching any real AWS credentials:

use Curentis\CloudFrontSigner\Contracts\Signer;

$this->mock(Signer::class)
    ->shouldReceive('sign')
    ->once()
    ->andReturn('https://cdn.example.com/videos/intro.mp4?Signature=...');

Testing

Run the test suite:

composer test

Fix code style with Laravel Pint:

composer pint --fix

Run static analysis with Larastan:

composer phpstan

License

Released under the Apache License 2.0.