Debugging Laravel Policies

Debugging Laravel Policies

This is relevant to Laravel 5.4 and above (probably)

Help! My laravel policy not working..."
Some debugging strategies to help with this.

  • The default Laravel Policy directory is app/Policies/yourModelPolicy.php

  • You must register your policies by specifying them in the AuthServiceProvider.php file at app/Providers

  • Have you forgotten to include your App<modelName> in AuthServiceProvider.php? The AuthServiceProvider won't be able to find them unless you've namespace them:

  • Or, instead forgotten to prefix (namespace) your classes with 'App'. e.g :

      protected $policies = [
      'App\Model' => 'App\Policies\ModelPolicy',
      'App\MyModel' => 'App\Policies\MyModelPolicy',
      ];
    

File: app/Policies/yourModelPolicy.php
or..

    use App\MyModel;
    protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
    MyModel::class => 'App\Policies\MyModelPolicy',
    ];

File: app/Policies/yourModelPolicy.php

  • Remember the's an implicit deny if your policy isn't found- so you might think your policy is being called when it's simply not being found and therefore rejected with a "This action is unauthorized." error
  • Start with checking via controller based checks, these are (probably) closer to the issue than blade access checks- work your way out from there.

Is your policy even being called?

Sometimes the poor mans debugging tool die("I'm here") is the most useful tool for just understanding where you're at- especially with the implicit deny potentially confusing the situation. Using die("I'm here") or a simple die("blah") or the prettier dd("blahh") can confirm that you're policy is actually being called as expected and not being misses entirely.

Go to your Policy, look for the policy method your authorising against (e.g. a 'view' policy) and see if in-fact your policy is being called at all:

File: www/app/Providers/AuthServiceProvider.php

...
namespace App\Policies;

use App\User;
use App\MyModel;
use Illuminate\Auth\Access\HandlesAuthorization;

class MyModelPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view the myModel.
     *
     * @param  \App\User  $user
     * @param  \App\myModel  $myModel
     * @return mixed
     */
    public function view(User $user, MyModel $myModel)
    {
      die("I'm being called...");
    }

...

If it's not being called, check that the policy is actually being checked / invoked.

How to check Laravel policy is being invoked

Make sure the policy is actually being invoked. Start with a controller based check for example:

File: www/app/Policies/MyModel.php

/**
 * Display the specified resource.
 *
 * @param  int  $id
 * @return \Illuminate\Http\Response
 */
public function show(MyModel $myModel)
{
    $this->authorize('view', $myModel);
    ...
}

This uses the Laravel Authorize Controller Helper to invoke the 'view' policy on your MyModelPolicy policy.

  • Are you putting your authorize check on the right controller? Check your routes file (www/routes/web.php or www/routes/api.php) to ensure your applying authentication to the controller that's being called.

Is Laravel ignoring all your policies because you have a before() method?

Larvel allows you to define [policy filters](Policy Filters) to bypass all other policies within that policy- often used for an admin user type. Make sure this isn't getting in the way of your policy- if you have defined a before method (see below) and it's returning true then Laravel will not check any of the other methods..

public function before($user, $ability)
    {
    if ($user->isAdmin()) {
    return true; //This would stop checks on any other policy methods!
    }
}

Read the docs Laravel Policies at the Laravel Autorisation Documentation, and seriously, Rubber Duck Debugging.

Collect recurring payments with Subscribie - Try Now