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

takdw's avatar
Level 11

Roles, Permissions and Scopes: Laravel Passport

I'm trying to implement scopes on the tokens Laravel Passport returns. Here is what I have so far.

app/Providers/AuthServiceProvider.php

use Laravel\Passport\Passport;
...
public function boot()
{
    $this->registerPolicies();

    Passport::tokensCan([
        'do-anything' => 'Perform any actions',
        ...,
    ]);
}

app/Http/Middleware/CheckRole.php

public function handle($request, Closure $next)
    {
        $role = Role::find($request->user()->role_id);
        if($role) {
            switch ($role->name) {
                case "admin":
                    $request->request->add([
                        'scope' => 'do-anything'
                    ]);
                    return $next($request);
                case "...":
                    ...
            }
        }
        return $next($request);
    }

routes/api.php

Route::middleware(['auth:api', 'check-role'])->group(function() {
    Route::get('/users', function() {
        return User::all();
    })->middleware(['scopes:do-anything']);
});

I keep on getting a 403 Error when ever I try to hit the /users endpoint from an authenticated user. The error message says, Invalid scope(s) provided. I have a feeling that my CheckRole middlware isn't sending the modified request values. What am I missing here?

0 likes
6 replies
D9705996's avatar

Why have you written your own middleware to add a scope? Can you not just add the correct scope on the request and use the default scopes middleware?

https://laravel.com/docs/5.7/passport#checking-scopes

You would still have your authorization layer in your application to ensure an non admin can't do admin tasks

takdw's avatar
Level 11

@d9705996 I have tried that. Its just I kept getting the 403: Invalid scope(s) provided error. I thought adding the scope value to the request before it reached the authorization layer would work.

If I were to add a value to a $request, is this the right approach to do so? The middleware.

Thanks,

D9705996's avatar

What you have should work without your custom middleware. Do you see anything useful In storage/logs/laravel.log

D9705996's avatar

Ah wait you have an array for scopes. Change it to a string

->middleware('scopes:do-anything');
takdw's avatar
takdw
OP
Best Answer
Level 11

@d9705996 You are right. My custom middleware was adding nothing to the app. I was going through the laravel.log file when I remembered something. Scopes are applied to tokens. And I completely forgot that and was thinking the user determines the scope. That's when I noticed my big mistake. The logic I added in the custom controller should live in the login method of the app. When the token is generated, the scope is associated with it. Then subsequent requests using that token can easily be checked for scope.

app/Http/Controllers/AuthController.php

public function login() {
    $user = User::whereEmail(request('username'))->first();

    if (! $user) {
        // return an error response
    }

    if (!Hash::check(request('password'), $user->password)) {
        // return an error response
    }

    $client = DB::table('oauth_clients')
        ->where('password_client', true)
        ->first();

    if (! $client) {
        // Passport not setup properly
    }

    $data = [
        'grant_type' => 'password',
        'client_id' => $client->id,
        'client_secret' => $client->secret,
        'username' => request('username'),
        'password' => request('password'),
    ];

    // here is where the scope should be added to the request
    $role = Role::find($user->role_id);
    if($role) {
        switch ($role->name) {
            case "admin":
                $data['scope'] = 'do-anything';
                break;
            case "manager":
                $data['scope'] = 'manage-request';
                break;
            case "...":
                ...
            default:
                break;
        }
    }

    $request = Request::create('/oauth/token', 'POST', $data);
    
    // check request and log in the user
}

Its was silly mistake on my part. Its working as intended now. Thank you very much for your help sir.

D9705996's avatar

Awesome. Glad you got your issue sorted. Can you please mark the discussion as resolved

Please or to participate in this conversation.