Securing Files with Temporary URLs in Laravel

Feature Image

In modern web applications, securely sharing files while controlling access is crucial. Laravel provides an elegant solution for generating temporary URLs that expire after a specified time, ensuring your files remain protected. This article demonstrates how to implement temporary URLs in Laravel, covering route configuration, controller methods, and service provider adjustments.

Why Use Temporary URLs?

Temporary URLs allow you to grant time-limited access to files stored in your application. This prevents unauthorized sharing or prolonged access to sensitive resources. Laravel simplifies this process using signed URLs with expiration timestamps and cryptographic signatures.

Step 1: Create a Controller

Start by creating a FileController to handle URL generation and file streaming. The controller includes two methods:

  • getTemporaryUrl: Generates a signed temporary URL for the requested file.
  • stream: Validates the URL signature and streams the file if valid.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;

class FileController extends Controller
{
    // Generate a temporary URL
    public function getTemporaryUrl(Request $request)
    {
        $path = $request->query('path');
        $expiration = now()->addMinutes(10); // URL expires in 10 minutes

        $temporaryUrl = Storage::temporaryUrl(
            $path,
            $expiration
        );

        return response()->json(['url' => $temporaryUrl]);
    }

    // Stream the file after validating the URL
    public function stream(Request $request)
    {
        // Validate the URL signature
        if (!URL::hasValidSignature($request)) {
            abort(403, 'Invalid or expired URL.');
        }

        $path = $request->query('path');

        // Check if the file exists
        if (!Storage::disk('local')->exists($path)) {
            abort(404, 'File not found.');
        }

        // Stream the file
        return Storage::disk('local')->response($path);
    }
}
    

Step 2: Configure Routes

Define routes in routes/web.php to map requests to the controller methods. Assign names to the routes for easier reference in the service provider.


use App\Http\Controllers\FileController;

Route::get('file/stream', [FileController::class, 'stream'])->name('stream');
Route::get('file/generate', [FileController::class, 'getTemporaryUrl'])->name('generate');
    

Step 3: Customize Temporary URL Generation

Modify AppServiceProvider to override Laravel's default temporary URL logic. This links the URL generation to the named route stream and includes the file path as a parameter.


<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\URL;
use DateTime;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        Storage::disk('local')->buildTemporaryUrlsUsing(
            function (string $path, DateTime $expiration, array $options) {
                return URL::temporarySignedRoute(
                    'stream',
                    $expiration,
                    array_merge($options, ['path' => $path])
                );
            }
        );
    }
}
    

How It Works

  1. Generate a Temporary URL: A client requests a URL via /file/generate?path=images/file.png. The server returns a signed URL like:

    
    http://127.0.0.1:8000/file/stream?expires=1736937021&path=images%2Ffile.png&signature=abc123
                

    The URL includes an expiration timestamp and a cryptographic signature.

  2. Access the File: When the URL is accessed, Laravel validates the signature and expiration time. If valid, the file is streamed directly from storage. Invalid or expired URLs return a 403 Forbidden error.

Benefits

  • Security: Files are inaccessible without a valid signature.
  • Controlled Access: URLs automatically expire, reducing the risk of unauthorized sharing.
  • Efficiency: Files are streamed without exposing their storage path.

Conclusion

By leveraging Laravel's built-in features for signed URLs, you can enhance file security with minimal effort. This approach ensures sensitive resources remain protected while providing a seamless user experience. Adjust the expiration time and error handling to suit your application’s needs.

Comments

Login to comment