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

threeel's avatar
Level 10

Policy always returns 403

Hello all i have been having an issue while testing an api endpoint

i have tried introducing a policy into the project and still trying to figure it out the policy is

    /**
     * Determine whether the user can view the lecture.
     *
     * @param \App\Models\User $user
     * @param \App\Models\Lecture $lecture
     * @return mixed
     */
    public function view(User $user,Lecture $lecture) {
        return true;
    }

the controller

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function index() {
        $this->authorize('view',Lecture::class);

        return ['data','meta'];
    }

Test

    public function test_that_lectures_are_viewed_publicly() {

        $response = $this->getJson($this->getEndpoint('lectures'));

        $response->assertOk();
        $response->assertJsonStructure(['data', 'meta']);

    }

public function getEndpoint($endpoint, $append = null) {

        if ($append) {
            return $this->endpoint_prefix . $endpoint . '/' . $append;
        }

        return $this->endpoint_prefix . $endpoint;

    }

i have registered the Policy in the Auth Service provider

    protected $policies = [
        // 'App\Model' => 'App\Policies\ModelPolicy',
        Course::class           => CoursePolicy::class,
        Lecture::class          => LecturePolicy::class,
        SubscriptionPlan::class => SubscriptionPlanPolicy::class,
    ];

 /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot() {

        $this->registerPolicies();

        Passport::routes();

        Gate::before(function($user, $ability) {

            return $user->isAdmin();
        });
    }

problem is that i always get a 403 if anyone could help would appreciate it. Laravel 5.8 is used

0 likes
7 replies
wilburpowery's avatar

Lecture::class just returns the name of the actual class not an instance.

Try using new Lecture in order to pass an instance of Lecture to your policy.

public function index() {
        $this->authorize('view', new Lecture);

        return ['data','meta'];
    }
diegoaurino's avatar

Hello, @threeel !

Also, try to change the protected $policies array. Instead of using the scope resolution operator to designate the class, like ::class, use the full autoload path, for example, 'App\Model' => 'App\Policies\ModelPolicy'.

Make sure your test method does not require authentication. If so, you need to authenticate first.

Hope this reply helps you. Let me know if so.

threeel's avatar
Level 10

@DIEGOAURINO - hey thanks for the reply i have tried that with no success. keep in mind that this is laravel 5.8 that i shouldn't have to do this.

diegoaurino's avatar

@THREEEL - I thought this was Laravel 0.1... Make sure there is no mistakes in the model and/or policies imports namespaces. Double check if your getEndpoint method is returning the correct path. Another point: your test says the "lectures" are open. So, you do not need a policy for the index. Do you? Also, take a look if other authentications, routes with the can key in the middleware method, gates or policies are not interfering in the process.

threeel's avatar
Level 10

@DIEGOAURINO - hey thanks for the reply. i have checked the policies namespace/path i used hardcoded paths. the problem is not just on lecture

something that maybe "different" from the normal implementation is that i am using passport for api authentication.

i am using the Passport::actingAs($user); in the tests

also something that i have noticed is that on the AuthServiceProvider

i have the

Gate::before(function($user, $ability) {
            return $user->isAdmin();
        });

which it should be allowing the request if i was running as admin but still not working

threeel's avatar
threeel
OP
Best Answer
Level 10

hello guys thanks for your support i have found my issue. it was actually twofold case one was

Gate::before(function($user, $ability) {
            return $user->isAdmin();
        });

so if you where a normal user and not admin this naturally returns false so that makes the result false

Gate::before(function($user, $ability) {
            if ($user->isAdmin()) {
                return true;
            }

        });

so with this if a user is admin will return true else it will proceed to the policy

the second actually comes from a previous comment @wilburpowery

where i replied that the documentation says that you suppose to send a full class name if it is not receiving an instance

 public function view(User $user, Lecture $lecture)
    {
        return $user->isSubscribed();
    }

the documentation actually refers to the case of create ex.

    public function create(User $user)
    {
        //
    }

so thank you all for your comment.

1 like

Please or to participate in this conversation.