Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to limit user actions with Laravel Passport Scopes + Password Grant Type

I have set up the Laravel Passport package for Laravel 5.3 just as described in the official documentation (https://laravel.com/docs/5.3/passport#introduction).

I want the API to be consumed by a mobile application, so I am trying to implement Password Grant Tokens. I have created a password grant client, and the token request process...

$response = $http->post('http://my-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'password',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'username' => '[email protected]',
        'password' => 'my-password',
        'scope' => '',
    ],
]);

...Just works as expected, returning an access-token and a refresh-token for one of my users.

But now I want to define some scopes so I can limit the access of users... Following the documentation again, I have them defined in boot method of AuthServiceProvider.php like:

Passport::tokensCan([
    'admin' => 'Perform every action',
    'user' => 'Perform only normal user actions',
]);

In this scenario, if a "malicious" normal user requested a token (using the above POST call) specifying 'scope' => 'admin', he or she would get an 'admin' token... and that is not what I want.

Thus, I would like to know how is the workflow in this situation to effectively limit the access to normal users, and where do I have to implement the scope validation logic.

Thanks in advance.

like image 784
andcl Avatar asked Dec 21 '16 13:12

andcl


2 Answers

One way to go about this would be to create a middleware

For example if you only want users with an email from example.com to request the admin domain you can do something like this

Example ScopeLogic.php middleware:

if ($request->input('grant_type') === 'password') {
    $scope = $request->input('scope');
    $username = $request->input('username');

    if ($scope === 'admin' && (strpos($username, '@example.com') === false)) {
        return response()->json(['message' => "Not authorized to request admin scope"], 401);
    }
}

return $next($request);

Of course, you would have to add this scope to your $routeMiddleware array in Kernel.php

protected $routeMiddleware = [
    ...
    'check-scopes' => \App\Http\Middleware\ScopeLogic::class
]

As well as wrap Passport::routes() in AuthServiceProvider.php to check for this middleware

\Route::group(['middleware' => 'check-scopes'], function() {
    Passport::routes();
});

Passport will also check that a correct username and passport combination was passed so you don't have to worry about that in the middleware

like image 131
Mauricio Trajano Avatar answered Sep 20 '22 20:09

Mauricio Trajano


In my opinion, I think what confuses most people with OAuth and APIs is that scopes are tied to "clients" and not the "resource owner" themselves. Clients should be able to talk to an API using an admin scope or no scopes at all if needed. If they use an admin-ish type scope together with user context (password grant, authorization code grant, etc), then there is no stopping them from making calls that require such a scope against that user in the API. To me, the only person that can truly be classified as malicious would be one who manages to steal an access token containing an admin scope. That is why API implementors are allowed to specify what scopes to grant a client and if it's a first party app that uses something like the Password Grant, then you as a user has no choice but to trust it with your data.

I don't know how one would do this and use the retrieved token inside another's mobile app but if you did try requesting a token manually yourself with an admin scope, then I really don't see anything wrong that (other than you giving the app more control with you set as user context, so it may even be counter productive?)

If you need more control than that, then you need to go past your API and create something like application-level permissions for each user inside your resource server.

like image 39
georaldc Avatar answered Sep 17 '22 20:09

georaldc