Load Blade assets with https in Laravel
Asked Answered
V

14

106

I am loading my css using this format: <link href="{{ asset('assets/mdi/css/materialdesignicons.min.css') }}" media="all" rel="stylesheet" type="text/css" /> and it loads fine for all http requests

But when I load my login page with SSL (https), I get a ...page... was loaded over HTTPS, but requested an insecure stylesheet 'http...

Can someone please tell me how do I make blade load assets over https instead of http?

Should I be trying to load the assets securely? Or is it not Blade's job?

Vipul answered 20/12, 2015 at 4:58 Comment(1)
I know it's been several years, but I would suggest unmarking my answer as the accepted answer and picking Scofield's Answer as the correct one. His is far more useful and flexible than my own, and this is a pretty high quality question that people are finding organically on their own.Neurotic
B
261

I had a problem with asset function when it's loaded resources through HTTP protocol when the website was using HTTPS, which is caused the "Mixed content" problem.

To fix that you need to add \URL::forceScheme('https') into your AppServiceProvider file.

So mine looks like this (Laravel 5.4):

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        if(config('app.env') === 'production') {
            \URL::forceScheme('https');
        }
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

This is helpful when you need https only on server (config('app.env') === 'production') and not locally, so don't need to force asset function to use https.

Benny answered 17/8, 2017 at 9:35 Comment(7)
this is a better answer, since I want to only use https on production serverRewrite
Agreed. While my answer might have addressed the question directly, this approach would likely be better in cases where you have multiple environments that may or may not be serving over HTTPS.Neurotic
Only on Production make better sense and fit my case.Disciplinary
I used this same pattern, but instead of just checking 'app.env', I looked at 'app.url'. If it starts with 'https', then I force the scheme.Heterosexual
This should be the accepted answer I believe. I had another problem with login form submission. Both fixed when I forced the https in the service provider class.Yamauchi
can use this as well if(!app()->isLocal()) { \URL::forceScheme('https'); }Rockel
This is no longer the right way of doing this. You should be using the TrustProxies middleware...Riebling
N
92

I believe secure_asset is what you're looking for.

<link href="{{ secure_asset('assets/mdi/css/materialdesignicons.min.css') }}" media="all" rel="stylesheet" type="text/css" />

5/15/2018 Edit: While my answer addresses the question directly, it's a bit dated given what Laravel can do nowadays; there may be cases where you want to force HTTPS on certain environments but not on others.

See Scofield's answer below for a more flexible solution to cover for these kinds of cases.

08/11/2020 Edit: Seriously guys, Scofield's Answer is better than mine and will provide more flexibility for differing environments. Give him your updoots.

Neurotic answered 20/12, 2015 at 5:5 Comment(5)
This will not work if you are working with virtual host on your local machine, insted of changing from asset to secure_asset you should update your AppServiceProvider->boot function ``` $url->forceScheme('https'); ``` you can also put this in if condition like this ``` if (env('APP_ENV') !== 'local') { $url->forceScheme('https'); } ``` and remember to run command "php artisan config:clear".Manque
@HiteshKumar Where did you hear that it "will not work"? This will work just fine on a virtual host on your local machine, just as long as you know how to generate and trust your own certificate. You can also review my edit from over two years ago pointing out that this answer is not as well-rounded as Scofield's answer below. Your suggestion to use artisan config:clear is also superfluous and does nothing in this scenario, since no configurations are changed in either my or Scofield's approaches.Neurotic
because I already tried, and I am suggesting "artisan config:clear" because of if condition of local and production environment this will clear add->config and load .env variables. This can work in older version of laravel but in letest it changed.Manque
This is not a valid solution since we need to change everywhere in the files wherever we've used.Treasurehouse
@Treasurehouse Yeah. We know. Look at all of the edits on this question. I had OP change the answer.Neurotic
S
61

There is a environment variable "ASSET_URL" where you put your app url with the http or https

ASSET_URL=https://your.app.url #for production

or

ASSET_URL=http://your.app.url #for local development
Spae answered 7/7, 2021 at 13:54 Comment(5)
This should be the accepted answer. Why write 10-20 lines of code when its already there.Tarp
This is the best answer! It works for meWeil
It works like a charm in v8.54. This solution is much better since all you have to do is override a default variable in your .env or create one if it's not there.Carnet
It works perfectly and is much simplerSkirmish
The @vite(['resources/css/app.css', 'resources/js/app.js']) helper in my master Blade template was constructing URLs with http instead of https (despite APP_URL specifying https). Adding ASSET_URL=${APP_URL} fixed it!Swope
B
38

I use @Scofield answer by use \URL::forceScheme('https'); This solution also worked to show https for all routes but this not worked for me for $request->url() it show http instead of https

so I used $this->app['request']->server->set('HTTPS', true); instead of \URL::forceScheme('https');

I'm using Laravel 5.4 and update .env file and appserviceproviders

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
use Log;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     *
     */
    public function boot()
    {
        If (env('APP_ENV') !== 'local') {
            $this->app['request']->server->set('HTTPS', true);
        }

        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

in my env file I've changed

APP_ENV=local to APP_ENV=development

APP_ENV=local for localhost APP_ENV=development/production for on working server

after changing env run this artisan command

php artisan config:clear

Hope It helps :-)

Blimp answered 17/1, 2018 at 9:47 Comment(2)
@NavaBogatee happy to hear this. :-)Blimp
config:clear is unnecessary if instead using env(), use config() or $this->app->environment()Wnw
C
15

An another approach would be to pass true as the second parameter.

/**
 * Generate an asset path for the application.
 *
 * @param  string  $path
 * @param  bool    $secure
 * @return string
 */
function asset($path, $secure = null)
{
    return app('url')->asset($path, $secure);
}

As you see below secure_asset simply calls asset with the second parameter true.

/**
 * Generate an asset path for the application.
 *
 * @param  string  $path
 * @return string
 */
function secure_asset($path)
{
    return asset($path, true);
}
Cornered answered 20/12, 2015 at 5:41 Comment(1)
Thank you for the alternative suggestion :)Vipul
A
11

Figuring out if the current Request is secure or not should not be your decision. Underlying Symfony\Component\HttpFoundation\Request has isSecure method that Laravel uses internally.

public function isSecure()
{
    if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) {
        return \in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true);
    }

    $https = $this->server->get('HTTPS');

    return !empty($https) && 'off' !== strtolower($https);
}

So if your server is not passing the HTTPS header with On, it should be passing X-FORWARDED-PROTO and must be allowed by your TrustProxies middleware.

If you are behind reverse-proxy you should find out your proxy pass IP - you can do this easily by getting the $_SERVER['REMOTE_ADDR'] variable and setting the IP to your TrustProxies middleware:

/**
 * The trusted proxies for this application.
 *
 * @var array
 */
protected $proxies = [
    '123.123.123.123',
];

Laravel (Symfony) will then automatically detect if the Request is secure or not and choose the protocol accordingly.

Aeromarine answered 28/8, 2018 at 2:18 Comment(0)
B
10

The problem is cloudflare on my local machines is working fine but online server not solution is

 public function boot()
    {

        if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&  $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
             \URL::forceScheme('https');
        }
    }
Bootblack answered 28/9, 2018 at 9:57 Comment(0)
R
8

Here is my configuration to make HTTPS working with assets. To enable this in production add REDIRECT_HTTPS=true in the .env file.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        if(env('REDIRECT_HTTPS'))
        {
            \URL::forceScheme('https');
        }

        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
Remuneration answered 20/9, 2017 at 12:15 Comment(0)
A
4

Improving even more the answer of colleague Paulo Gabriel above, which should have been accepted as an answer, for being extremely practical, in the .env file just insert this config if your APP_URL already contains https://:

ASSET_URL="${APP_URL}"
Atom answered 9/1, 2023 at 12:51 Comment(0)
A
1

in .env file please change the value local to production

APP_ENV=production
Agenda answered 25/9, 2021 at 7:13 Comment(0)
C
1

Instead of "{{ asset('assets/mdi/css/materialdesignicons.min.css') }}" use "{{ secure_asset('assets/mdi/css/materialdesignicons.min.css') }}"

Certify answered 26/3, 2022 at 19:8 Comment(0)
P
0

I ended up putting this in my blade file:

@if(parse_url(url('/'), PHP_URL_SCHEME) == 'HTTPS')
    <link rel="stylesheet" href="{{ secure_asset('assets/css/slider.css') }}">
    <link rel="stylesheet" href="{{ secure_asset('assets/css/dropdown.css') }}">
@else
    <link rel="stylesheet" href="{{ asset('assets/css/slider.css') }}">
    <link rel="stylesheet" href="{{ asset('assets/css/dropdown.css') }}">
@endif
Pileup answered 20/11, 2019 at 9:9 Comment(0)
A
0

While upgrading Laravel version from 5.4 to 5.5, I had the same issue.

Just add \URL::forceScheme('https'); in app/Providers/AppServiceProvider.php. It worked.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     *
     */
    public function boot()
    {
        \URL::forceScheme('https');
    }
...
Anderlecht answered 14/5, 2020 at 18:52 Comment(0)
E
0

I think a better solution would be to combine @Jan Richter's solution with @Ozan Kurt's answer.

Since @Richter's answer let you use Symfony's built-in isSecure() function, which is already integrated with Laravel's request, you can easily call it as $request->isSecure(), then use its return value to serve the assets via @Kurt's approach.

A sample code would be like this:

    protected function index(Request $req) {
        return view('index', [
            'isSecure' => $req->isSecure();
        ]);
    }
...
<link href="{{ asset('assets/mdi/css/materialdesignicons.min.css', $isSecure) }}" media="all" rel="stylesheet" type="text/css"/>
...

OR just use the Request directly from the blade:

@php ($isSecure = Request::isSecure())
<link href="{{ asset('assets/mdi/css/materialdesignicons.min.css', $isSecure) }}" media="all" rel="stylesheet" type="text/css"/>

EDITS


  • EDIT[0]: Fixed Ozan Kurt's answer link
  • EDIT[1]: Fixed both answer links (and edit's format)
Evildoer answered 10/10, 2023 at 10:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.