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

robinsonryan's avatar

Using data from Auth::user() in global scope

I need to add a global scope to the user model based on data from Auth::user(). For example, users belong to accounts, so users should only see other users that belong to their accounts. I need to scope by Auth::user()->account_id. However, after wasting hours trying to get it to work, I found this - https://github.com/laravel/framework/issues/18218. Basically, it can't be done.

I created a local scope that works great for scoping by Account, but I also need to scope by Departments and Roles and potentially other attributes all at once. Writing local scopes for all of them and chaining them together will get tedious and causes other problems as the app grows. Global scopes are the answer.

So, I created a new model AuthUser model class and used that to handle authentication. My regular User model will hold the global scopes that access Auth::user() which is now based on the AuthUser model. It seemed like a great solution. However, my users also have roles and the roles implementation uses polymorphic relationships that reference the model in a table column ('model_type' => 'App\User').

How can I implement a single user model class that will allow me access Auth::user() in a global scope? Or, implement two classes that won't mess with my polymorphic relationships?

Relevant code:

Won't work

// Scopes\AccountScope.php

class AccountScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
    $builder->where('account_id', Auth::user()->account_id);
    }
}
// App\Models\AuthUser

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use App\Scopes\AccountScope;
use Auth;


class AuthUser extends Authenticatable
{
    use HasRoles;

    //...

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new AccountScope);
    }
}

Works, but messes up polymorphic relationships (specifically on Roles, but I have others in the app).

// App\Models\AuthUser

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use App\Scopes\AccountScope;
use Auth;


class AuthUser extends Authenticatable
{
    use HasRoles;

    //...
}
// App\Models\User

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use App\Scopes\AccountScope;
use Auth;

class User extends Model
{
    use HasRoles;

    //...

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new AccountScope);
    }

    //...
}


// SomeController.php

Auth::user()->hasRole('admin')  //returns false

$user = User::find(Auth::id())->hasRole('admin')  //returns true

0 likes
5 replies
Snapey's avatar
Snapey
Best Answer
Level 122

I created a scope class that could be added to any model that needed filtering by the tenant_id


<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class TenancyScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('tenant_id', session('tenancy'));
    }
}

The scope gets the 'tenancy' from the session. It is added to the session as the user logs in, or, if they have more than one tenancy then they are redirected to a page that allows them to pick one.

Then in models that should be constrained by the tenancy;

    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new Scopes\TenancyScope);
    }

2 likes
Snapey's avatar

Some of this you covered, but my difference is the use of session to store the required attributes for the scope(s)

Clearly you cannot add the scope to the user model itself or you get the catch22 with the infinite looping

robinsonryan's avatar

Yep, when I first tried it I was getting out of memory errors due to the infinite loop. The session option looks promising. Have you found any downsides to getting the data from session vs. directly from the database?

Also, if I go that route would setting tenancy in the authenticated method of my login controller be an appropriate place to do so?

protected function authenticated(Request $request, $user)
    {
        // set tenancy here
    }
Snapey's avatar

Yes, that would be a good place to add it.

fadzli's avatar

I know this is quite old but somehow I found this thread while looking solution to get the Auth::user() in global scope.

I believe there is a PR regarding this issue https://stackoverflow.com/a/59298314/8696111. Try to do the Auth::hasUser() check first then call the Auth::user()

public function apply(Builder $builder, Model $model)
{
    if (\Auth::hasUser()) {
        if ( \Auth::user()->hasRole('admin')) {
            $builder->where('id', \Auth::user()->id);
        }
    }
}
   			
5 likes

Please or to participate in this conversation.