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

Vilfago's avatar
Level 20

Dynamically allow access to guest without authenticated them

Hello everyone,

I have the following situation : A forum with many categories (i.e. channel if I take the word use here). User are assigned to one or many groups. In the admin dashboard we can allow or deny access to each category for each group. In this dashboard, I have a group named "Guest" to allow or deny access to guest.

I protected the categories as follow :

Route::get('/forum/{forumcategory}', 'Forum\ForumCategoryController@index')
                ->middleware('can:read,forumcategory')
                ->name('forumcategory');

And it works well for authenticated user. But obviously, as guest isn't authenticated, it's fail.

I found a workaround using an authentification in the boot function of Provider

if(!Auth::check())
{
    Auth::onceUsingId($guest Id);
}

But there is two thing I don't like :

  • I have a "guest user" in my database, which is strange to me
  • With this method, the app consider that there is a logged user, and thus show a link to the profile, and a logout button (and other stuff for logged user)... I can change that, but I think there is a better/cleaner way.

I don't want to exclude some category in the code, as I want that the admin can change the access to guest from the admin panel.

Any help or thoughts on how handle this?

I thought I can create a fake user model, but I don't know how to pass it in the middleware without authenticate it...

Thanks for your help !

Vilfago

0 likes
2 replies
Vilfago's avatar
Level 20

After a few research, I'm working this way... but still not sure it's the best way :

  • before the middleware \Illuminate\Auth\Middleware\Authorize::class,, I go through the following middleware :
public function handle($request, Closure $next){
    if (!Auth::check()) {
        Auth::onceUsingId($guestId);
    } 
        
    return $next($request);
}

and after \Illuminate\Auth\Middleware\Authorize::class,, I go through :

public function handle($request, Closure $next){
    if(Auth::id() == $guestId){
        Auth::logout();
    }

    return $next($request);
}

It works, but still need a "guest user" in my database...

Vilfago's avatar
Level 20

I found a solution, but open if someone has an easier one.

  1. Create a new "Authentication guard" (name guest) with it's own "User Provider.
//config/auth.php
   /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------

    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],

        'guest' => [
            'driver' => 'session',
            'provider' => 'guests',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------

    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        'guests' => [
            'driver' => 'guest',
            'model' => App\Models\Guest::class,
        ],
    ],
  1. In the provider, override updateRememberToken() to avoid saving something in the database when logout
class GuestProvider extends EloquentUserProvider { 

    public function updateRememberToken(UserContract $user, $token)
    {

    }
}
  1. Create a middleware before the middleware \Illuminate\Auth\Middleware\Authorize::class to authenticate the guest and change the default guard on the fly.
public function handle($request, Closure $next)
    {
    if (!Auth::check()) {
            Auth::guard('guest')->login(new Guest);
            config(['auth.defaults.guard' => 'guest']);
    }

        return $next($request);
    }
  1. Let Laravel manage the permission as if was standard
  2. "Logout" the guest in the following middleware, and set the default guard back to the default one.
    public function handle($request, Closure $next)
    {
    
    if(Auth::id() == null){
      Auth::guard('guest')->logout();
      config(['auth.defaults.guard' => 'web']);
    }

        return $next($request);
    }

It works, but maybe someone has an easier solution ?

Please or to participate in this conversation.