Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Passport's Password Grant Flow for First-party Apps

I'm using Laravel Passport to give access to some parts of my API to third-party apps.

But, I also use my own API through my own first-party Native Android App. So, I looked over the whole internet for the best practice in this case, but getting stuck to get to a conclusion.

Here are the possibilities I found:

Possibility #01

I can follow the User Credential Password Grant Flow.
In this case I need to pass a client_secret and client_id to the authorization server. In order to keep them safe I can't write them in my mobile application's source code (APKs are decompilable...).

So, I have 2 choices.

Possibility #01 - Choice A

Proxyfying through my own server and inject the secret before calling the oauth endpoint:

$proxy = Request::create('/oauth/token', 'post', [
    'grant_type' => 'password',
    'client_id' => 1,
    'client_secret' => 'myownclientsecretishere',
    'username' => $username,
    'password' => $password
]);
$proxy->headers->set('Accept', 'application/json');
$response = app()->handle($proxy);

Possibility #01 - Choice B

Inject the secret when calling the oauth endpoint using a Middleware:

class InjectPasswordGrantSecret
{
    public function handle($request, Closure $next)
    {
        $request->request->add([
            'client_id' => 1,
            'client_secret' => 'myownclientsecretishere'
        ]);
        return $next($request);
    }
}

These are working examples, but they are also greedy in resources.. I tried to use Apache benchmark on my local machine and I got something like 9 requests/second.

Possibility #02

I can follow the Personal Access Grant.
This one doesn't look like a standard in OAuth2, it allows us to create a token through any custom route, just like this:

if (! auth()->attempt(compact('username', 'password'))) {
    return error_response(__('auth.failed'));
}
$user = auth()->user();
$token = $user->createToken(null)->accessToken;

Using Apache benchmark I get better result (something like 30 requests/second).

But, token lifetime is not configurable by default and is set to 1 year (note that there are workarounds to get this lifetime configurable using a Custom Provider).

I am really wondering if this solution is meant to be used in a production environment.

Initially, I used JWT tymon library because I only had my own app. But now that I need to get it to work with first-party AND third-party apps, I thought that OAuth2 (through Laravel Passport) would be a good solution...

I hope someone can help me out with this, and explain what could be a good solution to get it to work securely and [not slowly] on production servers.

like image 524
Marc Avatar asked Oct 26 '18 14:10

Marc


1 Answers

Here is the page that I always refer: https://oauth2.thephpleague.com/authorization-server/which-grant/ enter image description here

It says

We strongly recommend that you use the Authorization Code flow over the Password grant for several reasons. We eliminate the password grant option.

Then, it says clearly in the diagram that you should use

Authorization Code Grant with PKCE

and also indicates that

If the client is a web application that has runs entirely on the front end (e.g. a single page web application) or a native application such as a mobile app you should implement the authorization code grant with the PKCE extension. You can read further in the document.

Additionally, there is a good tutorial here explaining every detail of the flow with an example: https://auth0.com/docs/architecture-scenarios/mobile-api

I hope these help.

PS: When the time I needed to authorize my users in my first party application, I had used password grant by referencing this very chart. However, it seems like it changed and password grant is now not a best practice anymore and is not recommended.

like image 164
Onur Demir Avatar answered Oct 15 '22 11:10

Onur Demir