Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

kuns25's avatar

How to access private files stored in Amazon s3 bucket and display in Laravel blade

I have a profile page where user uploads their driving license image, I'm storing these images in Amazon s3 bucket with private visibility $path = $request->file('image')->store('avatars', 's3') . I want to display this image in user profile page, As the files are private to access these images i found solution that i have to create temporary URLs to access the image as follows

        $image_path = Storage::disk('s3')->temporaryUrl(
            'avatars/'.$license->imageName,
            Carbon::now()->addMinutes(20)
        );

The $image_path is returning me temporary path of url which I can use in <img src="{{$image_path}}" tag but issue with this solution is even if I copy and paste this temporary url in incognito mode its returning the image , as 20 minutes time is set , this solution my client is not accepting as image is accessible in private window even though its temporary access.

another solution that i found without generating temporary url is by using return $src = Storage::disk('s3')->response('avatars/'.$image->filename); if i return this line it will print image in the browser. but i want do display image in the blade file if i print this $src in the blade file {{src}} is outputing HTTP/1.0 200 OK Cache-Control: no-cache, private Content-Disposition: inline; filename=vkMv0NcQGBoq3U9C7DUNhzujA6tLEp8dQEIMJCO2.jpg Content-Length: 1630 Content-Type: image/jpeg Date: Wed, 03 Nov 2021 10:07:56 GMT .

Please guide is there any way i can print these image in blade , or any other way to access private files without generating temporary urls

0 likes
17 replies
martinbean's avatar

@kuns25 Create an endpoint that returns the image if the user is authenticated and authorised to view that file:

class DrivingLicenseImageController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('cache.headers:private');
    }

    public function show()
    {
        $user = $request->user();

        return Storage::get($user->driving_license_image_path);
    }
}

Then use the URL of this endpoint as your <img> source.

1 like
kuns25's avatar

@martinbean hey thanks for the reply, when I'm returning Storage Storage::disk('s3')->get('avatars/PQYVXC3SCmKmJDAOf943F6ejgSh1aLvJ6TNWW7LM.jpg'); I'm getting some random text , can you tell me how to convert it to the image , Screenshot -> https://ibb.co/K9BfTx3

martinbean's avatar

@kuns25 You’ll need to add the appropriate Content-Type header to tell the browser what it is you’re actually returning.

$content = Storage::get($user->driving_license_image_path);

return response($content)->header('Content-Type', 'image/jpeg');
2 likes
kuns25's avatar

Hey yes it's returning the response as an image in the browser now, I'm still a little confused about how to put this image in a variable and display in the blade file , really appreciate all the support thanks

martinbean's avatar
Level 80

I'm still a little confused about how to put this image in a variable and display in the blade file , really appreciate all the support thanks

@kuns25 You don’t put it in a variable. You use the URL of the controller like any other image URL.

Route::get('/driving-license-image', [DrivingLicenseImageController::class, 'show'])->name('driving_license_image.show');
<img src="{{ route('driving_license_image.show') }}">
3 likes
kuns25's avatar

@martinbean to access the image sort of facing n+1 problem just to retrieve images I've to run 1 SQL query while showing this in the blade list via route model binding its executing SQL query on each item , is there any other way I can prevent the SQL query

    public function image(Driver $driver)
    {
  
        $image = Storage::disk('s3')->get($driver->file_path);
        return response($image)->header('Content-Type', 'image');


    }

Snapey's avatar

@kuns25 you should be accepting the filepath in the call to your image route, then you don't need to perform 2 more queries to resolve the driver and the image

If you are worried that the image path could be tampered with, you can use signed URLs

kuns25's avatar

@Snapey thanks for the reply, sorry i couldn't understand how to accet the file path in image route, the images are stored in private aws s3 bucket

Snapey's avatar

@kuns25

from Martin, adjusted

Route::get('/driving-license-image/{path}', [DrivingLicenseImageController::class, 'show'])->name('driving_license_image.show');

view

<img src="{{ route('driving_license_image.show', ['path' => $driver->file_path]) }}">

controller

    public function image($path)
    {
        $image = Storage::disk('s3')->get($path);
        return response($image)->header('Content-Type', 'image');
    }

you may want to add additional security.

If you use unguessable filenames you could make the bucket public and just share the url instead of downloading it first.

1 like
kuns25's avatar

@Snapey Awesome, Thanks understood, stupid of me not to think that way

kuns25's avatar

@snapey can you tell me if there's any huge speed performance difference between keeping private images & generating temporary urls and keeping images in public bucket with unguessable name & accessing the em with direct urls

martinbean's avatar

keeping images in public bucket with unguessable name & accessing the em with direct urls

@kuns25 This is security by obscurity. It’s not what you want. Especially when dealing with sensitive, government-issued documents like driving licenses.

1 like

Please or to participate in this conversation.