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

ella-stinnes's avatar

Policy for belongsToMany Pivot Table

  • projects
  • project_user
  • users

I want to create an authorization policy for the 'project_user' pivot table to define who is able to assign projects to a given user.

At the moment, I don't have a ProjectUser model class. Will I need to create this for the ProjectUserPolicy?

1 like
9 replies
vincent15000's avatar

It depends on the business logic.

Can you explain the rule that explains if a user can assign projects to other users ?

It is inside a team with a team leader ?

It this authorized only for the manager ?

... ?

ella-stinnes's avatar
  • Full Admin - Can link any user to projects that are associated with the users' company.

  • Company Admin - Can only view users associated with their own company. They can therefore only link these users to projects associated with their company.

Jsanwo64's avatar
Level 11

You don’t need a ProjectUser model just to authorize “assigning a project to a user”.

In Laravel, the “pivot” is usually not treated as a first-class resource for authorization; instead you authorize the action on one of the real models (most commonly User or Project) and pass the other model(s) as arguments.

  1. Define a custom ability on UserPolicy
// app/Policies/UserPolicy.php

public function assignProject(User $actor, User $target, Project $project): bool
{
    // 1) Full Admin: can link users to projects within the user's company
    if ($actor->isFullAdmin()) {
        return $target->company_id === $project->company_id;
    }

    // 2) Company Admin: only within their own company
    if ($actor->isCompanyAdmin()) {
        return $actor->company_id === $target->company_id
            && $actor->company_id === $project->company_id;
    }

    return false;
}
  1. Use it in controller (best place, because you have all objects)
public function update(User $user, Request $request)
{
    $project = Project::findOrFail($request->project_id);

    $this->authorize('assignProject', [$user, $project]);

    $user->projects()->syncWithoutDetaching([$project->id]);
}

Route middleware: possible, but you’ll still need the objects

Route ->can() works well when your policy method can be resolved from route params. Since the ability needs User + Project, your route must provide both:

Route::post('/users/{user}/projects/{project}', [UserProjectController::class, 'store'])
    ->can('assignProject', ['user', 'project']);

This calls UserPolicy@assignProject(auth()->user(), $user, $project).

If your “edit” page doesn’t include {project} in the URL, then ->can() can only authorize a broader ability like “canManageUserProjects” (no specific project yet).
3 likes
ella-stinnes's avatar

My solution of a policy for a pivot table wasn't mentioned in the docs, so your explanation was what I was looking for and makes sense - thank you!

2 likes

Please or to participate in this conversation.