running laravel horizon in production throw a 403 error when requesting domain/horizon
Asked Answered
L

6

9

I have testet laravel Horizon on my local environment and everything is working as expected. When I am switching to production domain/horizon throws a 403 error. I have set the gate in HorizonServiceProvider as stated in the documentation - First step is just to get access without auth. My gate now looks like this:

{
    Gate::define('viewHorizon', function ($user = null) {
        return true;
    });
}

Can anyone suggest what I am missing?

link to 403 error link to 401 error - Dashboard without data

Leveille answered 17/4, 2020 at 20:42 Comment(0)
E
16

Check this GitHub comment: https://github.com/laravel/horizon/issues/563#issuecomment-480882947

You may have to register Horizon's service provider.

In config/app.php:

'providers' => [
        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
    ...
        App\Providers\TelescopeServiceProvider::class,
        App\Providers\HorizonServiceProvider::class,
    ],
Eccrinology answered 18/4, 2020 at 5:59 Comment(2)
Thanks for your reply - I already did that, or composer did it for me :)Leveille
Are you using non-default guards? The last comment on GitHub mentions this specific case.Eccrinology
E
10

The error it's because horizon it's first go to the boot method, so i recommended you in your HorizonServiceProvider.php edit the boot method to allow your request like this:

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        Horizon::auth(function ($request) {
            if ($request->ajax()){
                return true;
            }
            else if (isset($request->let_me_go) && $request->let_me_go == 'ok'){
                return true;
            }else{
                throw new UnauthorizedHttpException('Unauthorized');
            }
        });
    }

So when you will go to your production server need to pass the parameter like this:

my-production-site.com/horizon/dashboard?let_me_go=ok

Exurb answered 18/4, 2020 at 5:55 Comment(3)
It got me a step further! It now loads the dashboard but it can't get the data. the stats, master and workload call is returning a 401 - See link in original postLeveille
For testing - and moving forward I just changed the else statement to also returning true. Guess I will run without Auth for now :)Leveille
Brilliant, what a lost cost solution!Calmas
A
9

You need to add the following method to App\Providers\HorizonServiceProvider class:

class HorizonServiceProvider extends ServiceProvider {
    
    // ...

    protected function authorization()
    {
        Horizon::auth(function () {
            return true;
        });
    }
}

This method overrides the parent method that authenticates HTTP requests.

Almanac answered 22/8, 2021 at 21:35 Comment(0)
V
4

For me, the problem was that I'd set in app\Providers\HorizonServiceProvider.php:

/**
 * Register the Horizon gate.
 *
 * This gate determines who can access Horizon in non-local environments.
 *
 * @return void
 */
protected function gate() {
    Gate::define('viewHorizon', function ($user) {//https://laravel.com/docs/7.x/horizon#dashboard-authorization            
        return $user->id === \App\Constants\Permissions::ADMIN_USER_ID;
    });
}

And then I'd forgotten that I'd therefore need to log in at example.com/login before I'd be allowed to visit example.com/horizon.

See https://github.com/laravel/horizon/issues/563#issuecomment-500821983 and https://laravel.com/docs/8.x/horizon#dashboard-authorization

Venable answered 19/4, 2021 at 11:6 Comment(0)
B
1

According to the documentation of laravel on version 10.* you must update the HorizonServiceProvider on method gate() like this:

protected function gate(): void
{
    Gate::define('viewHorizon', function (User $user = null) {
        // return in_array($user->email, [
        //     //
        // ]);
        return true;
    });
}
Bistort answered 5/3 at 3:54 Comment(0)
W
0

Removing the second parameter [$request->user()] in the authorization() method allowed the Gate check() to execute. Otherwise, it was always returning false no matter what was inside the define() function

/**
 * Configure the Horizon authorization services.
 *
 * @return void
 */
protected function authorization()
{
    $this->gate();

    Horizon::auth(function ($request) {
        return Gate::check('viewHorizon', []) ||
            app()->environment('local');
    });
}

/**
 * Register the Horizon gate.
 *
 * This gate determines who can access Horizon in non-local environments.
 *
 * @return void
 */
protected function gate()
{
    Gate::define('viewHorizon', function ($user = null) {
        return $user->isAdmin();
    });
}
Waldenburg answered 28/11, 2022 at 0:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.