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

bearbytestudio's avatar

Can I scope spatie permissions user->role against another resource?

Hi!

I'm using Spatie Permissions package for authorization in my app. I need to add roles/permissions for a user against another resource. In my app, i have a User mode, a Location model and an Invoice mode. Invoices belong to a location, a user can see an invoice if they have access to the Location. I would like this to be controlled with Roles / Permissions. If the user has a certain role against the location, they can do different things.

For example:

  • A user can edit a particular invoice if they have a certain role on the location
  • A user can view any Invoice if they have an admin role for the Location

Any help welcome!

0 likes
5 replies
LaryAI's avatar
Level 58

To achieve this functionality using the Spatie Permissions package, you can implement a custom solution that scopes user roles and permissions to specific resources, such as a Location. Here's a step-by-step guide on how you can set this up:

Step 1: Define Relationships

First, ensure that your models have the necessary relationships. You need to establish a relationship between User, Location, and Invoice.

// User.php
public function locations()
{
    return $this->belongsToMany(Location::class);
}

// Location.php
public function users()
{
    return $this->belongsToMany(User::class);
}

public function invoices()
{
    return $this->hasMany(Invoice::class);
}

// Invoice.php
public function location()
{
    return $this->belongsTo(Location::class);
}

Step 2: Assign Roles to Users for Specific Locations

You can use a pivot table to manage roles for users at specific locations. For example, you might have a location_user table with user_id, location_id, and role_id.

Step 3: Check Permissions

Create a method to check if a user has a specific role for a given location. You can add this method to your User model.

// User.php
public function hasRoleForLocation($roleName, Location $location)
{
    return $this->locations()
                ->where('location_id', $location->id)
                ->wherePivot('role_id', Role::where('name', $roleName)->first()->id)
                ->exists();
}

Step 4: Implement Access Control Logic

Use the method you created to control access to invoices based on the user's role for the location.

// In your controller or service
public function canEditInvoice(User $user, Invoice $invoice)
{
    $location = $invoice->location;

    return $user->hasRoleForLocation('editor', $location);
}

public function canViewInvoice(User $user, Invoice $invoice)
{
    $location = $invoice->location;

    return $user->hasRoleForLocation('admin', $location) || $user->hasRoleForLocation('viewer', $location);
}

Step 5: Use Middleware or Gates

You can use Laravel's authorization features like middleware or gates to enforce these checks in your application.

// In a policy or controller
public function view(User $user, Invoice $invoice)
{
    return $user->canViewInvoice($invoice);
}

public function edit(User $user, Invoice $invoice)
{
    return $user->canEditInvoice($invoice);
}

Conclusion

By following these steps, you can scope user roles and permissions to specific resources like Location using the Spatie Permissions package. This approach allows you to manage access control dynamically based on the user's role for a particular location.

bearbytestudio's avatar

@tisuchi Hey, yep I've been through the docs. Which bit in particular on that page do you think solves my problem?

1 like
tisuchi's avatar

@bearbytestudio Apology if my comment sounds vague to you!

Here was my idea:

"Using Permissions via a Model"

Assign and check roles for a Location. This ensures users can only edit or view invoices for that specific location.

For example:

$location = Location::find(1);
$user->assignRole('manager', $location);

// Check if the user has a role for a specific location
$user->hasRole('manager', $location); // true

"Scoping Permissions"

Grant scoped permissions (e.g., edit-invoice) specific to a Location, providing fine-grained control.

For example:

$location = Location::find(1);
$user->givePermissionTo('edit-invoice', $location);

// Check if the user has permission scoped to the location
$user->can('edit-invoice', $location); // true

Both explanations are in the documents you mentioned. If I understand you right, this document is still valid for you. So, I am sharing this link: https://spatie.be/docs/laravel-permission/v6/basic-usage/role-permissions

1 like
bearbytestudio's avatar

@tisuchi Hey! Thanks for your reply.

That's exactly what I'm after, however, that functionality doesn't seem possible, nor listed in the docs?

$location = Location::find(1);
$user->assignRole('manager', $location);
1 like

Please or to participate in this conversation.