19

I'm using Laravel 6.7 and attempting to use Passport for user authentication.

I'm able to create an access token for the user when they register. Here is the code:

$user = User::create($input);
$user->createToken('auth-token');

This access token has an expiration of 15 minutes as I defined in my AuthServiceProvider.php file boot() function like so:

Passport::personalAccessTokensExpireIn(Carbon::now()->addMinutes(15));

I want to refresh it using a refresh token but can't seem to understand how.

I've looked everywhere (including the Laravel website) and they're all telling me to do this:

$http = new GuzzleHttp\Client;

$response = $http->post('http://your-app.com/oauth/token', [
    'form_params' => [
        'grant_type' => 'refresh_token',
        'refresh_token' => 'the-refresh-token',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => '',
    ],
]);

Without any clear explanation as to what the values 'the-refresh-token', 'client-id' and 'client-secret' are meant to be.

One answer on stack overflow said the following:

you must send old refresh-token ('refresh_token' => 'the-refresh-token') and this code produces a new token and refresh-refresh.

But I don't have a refresh token, I'm trying to create one. Do I just create a random string?

UndercoverCoder
  • 953
  • 3
  • 13
  • 28
  • 1
    What grant type are you using? How are you using the API? A javascript app? Mobile app? – Alec Joy Dec 13 '19 at 22:17
  • @AlecJoy Sory for not being clear, the API is built using the Laravel Framework for PHP. The endpoint will be accessed by a mobile app built using the Flutter framework for the Dart language. – UndercoverCoder Dec 13 '19 at 22:22
  • @AlecJoy As for the grant type, I'm not too sure what that is. I'm doing some research on that. – UndercoverCoder Dec 13 '19 at 22:23
  • Okay, for a first party application consuming your own api it's best to use the Password Grant token type https://laravel.com/docs/5.8/passport#password-grant-tokens. While you can set a short expiration time on these, there's really no reason to as it's just like logging in to your service through a browser. Short lived tokens are more meant for third party integrations. – Alec Joy Dec 13 '19 at 22:28
  • @AlecJoy Ahhhhhhhhhhhhhh that makes so much sense, just reading through the link you sent. Thank you so much :). I'm a bit of a newbie at this stuff, learning it has been a headache. – UndercoverCoder Dec 13 '19 at 22:36
  • 1
    That's what the internet is for! Have you heard of Laracasts by any chance? They provide a ton of video tutorials for laravel specific stuff. There content on passport pretty sparse but there Laravel 6 from scratch series might be a good place to start and it's free https://laracasts.com/series/laravel-6-from-scratch – Alec Joy Dec 13 '19 at 22:42
  • @AlecJoy Thanks, I'll give it a look :) – UndercoverCoder Dec 13 '19 at 22:49

2 Answers2

16

Using Password Grant Tokens

From: Laravel Docs: Password Grant Tokens

The OAuth2 password grant allows your other first-party clients, such as a mobile application, to obtain an access token using an e-mail address / username and password.

First you need to generate a Password Grant Client by:

php artisan passport:client --password

This will give you a client_id and a client_secret

So next you can implement your login in your Mobile app as follow:

POST
http://your-app.com/oauth/token

Body:
{
  'grant_type' => 'password',
  'client_id' => 'client-id',
  'client_secret' => 'client-secret',
  'username' => 'taylor@laravel.com',
  'password' => 'my-password',
  'scope' => '',
}

With the result of:

{
  "token_type": "Bearer",
  "expires_in": 300,
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjAyMGM1YTQ2MzM5ZTAxNjBjODViOWUyMGE0YTAxYzhmOWYzOTZkYjlhMmM1OWZiNjk0NDVjZTZlYTIyMmUyZmEyNDZmYzQ0MTc4M2NjNjIyIn0.eyJhdWQiOiI1MSIsImp0aSI6IjAyMGM1YTQ2MzM5ZTAxNjBjODViOWUyMGE0YTAxYzhmOWYzOTZkYjlhMmM1OWZiNjk0NDVjZTZlYTIyMmUyZmEyNDZmYzQ0MTc4M2NjNjIyIiwiaWF0IjoxNTczMjIxMTk0LCJuYmYiOjE1NzMyMjExOTQsImV4cCI6MTU3MzIyMTQ5NCwic3ViIjoiNWZhNzNkNjAtYzliNC0xMWU5LThiMDEtNjFmNDI4YjYyNTdiIiwic2NvcGVzIjpbXX0.EmmKwdr_tLUmN08MxnleCqIU0zDk8-pyecOaz-tQ2OBZa-UBsFe2SoaD0jqq_0t1BZHBiayO5qHFY6M459mXTPRNJM8Bx7MC1X_4GPHrozKMuymZ3Ham3J00UtsGHcF2gG39YcUnmhbDhiFefO8VGU-2e_2q2qWAFvO_lUB4CrcrVQ3o8-4o3mwXpmWbcoDbqiQwga_0-SMo8gYIFlh4OaO0Z_bCWsJaspUdRra672BV49une5uPlANLIinCthFHgcT_9t48z_wOzEHbVhuogMr5ObkJAy0rXTQLyvprale5EaNTPR0s9Fp1wvMtd08m7Pbdz2XLCShuIrE7cY8U8NZydxvX3aFqUOcqkmlvEGRkr3B6utjNQW19I7bKw9aIBBczoCCBmIqkqBuQFQziV3dQ7qQYJyKqr0n_mSyVzCllJ4nhWcV4hwny2KVQoszxjVMoVEzWEXsJSmxfWE4NHMYb0wmid6K_COCGzHRhfqtg_llySP_w2N0us2Ri92LyVovIJI0w2_ze0MBmyvS37OYIOLV3bCZcsVhnf9QCxAE6NAXXwgzYEj7Y0Q-7GkbOCDWrVghih3-engZj36dTBo_i4YJc5iygRlzLCW8AFtZig6mW6Veb9ITsSu_yTefCbZVPG4G0MjBhk03kSnLJGeyWeEAIBapdeEI7Vf8VsXo",
  "refresh_token": "def50200a4c2c3670e62fe28d61c38b66f0d4d85f5a576c0a3914cf9767d91027102bd9ab0a17e9e149266be2443f6ef2c25e092d4c17d2a813ca59b1df608dcfc120596c2ed72ffe7dd0a1db3bc7511ec905a65c63551239581a1c13c3c0b53fd0f8db97d2b49763f5bd98b7624a432d7e82161cc9e543d3e2550f73d6bcea0014aa0d4f72c2eb3edfe2f256fae1a8ea69270735be98a85b7040e33194eb449187b67aa0dbb10f75bdf620b6416c12756e96449e92aa6ad7b56be53876113a9d17d93c1039f54647040ce8acd7f242684d0b0aa1835267dbc6bab87c6b2a7862ca3bcd8396ae7c912b03ee3df7d471f74b96d0c48ec76a55ff05762227722ffb99ecb12f30fae9042b078383678492ef73e5fedfb0085a30a9511bc94588edd5a171e0650a092bb9c37e7571aeb6d0b6d9048189ab0fa16d48477e6d51e81efbe762af34c46ed2da1862528c24d00f0139f3e74eccbefd06a7dd238ccff85b9cbec68e2e7483a9fb2f4bc314d81d48f3dbbe0a9c8b42bd76bc4ad57fa2afad52092c5339f9461"
}

If you want to refresh an expired token you will do a request to /oauth/token with the POST method

And with the body:

{
  'grant_type' => 'refresh_token',
  'refresh_token' => 'the-refresh-token',
  'client_id' => 'client-id',
  'client_secret' => 'client-secret',
  'scope' => '',
} 

Put the previous refresh_token, client_id, client_secret and you will get another response containing other tokens

loic.lopez
  • 2,013
  • 2
  • 21
  • 42
  • User must be logged for refreshing its expired token? Is that posible? – Zalo Jun 04 '20 at 07:45
  • 1
    @Zalo Hi, in order to have a 'refresh_token' you must do a request to: "http://your-app.com/oauth/token" which is a log method that return an "access_token" and a "refresh_token" so you can assume after "/oauth/token" request, the user is logged – loic.lopez Jun 04 '20 at 15:42
  • @loic.lopez Do you know how to retrieve access token, and refresh token after the initial creation. I have already created those but I need them in controller. Also, how to log out the user with that access token? – VijayRana Apr 09 '22 at 14:23
  • @VijayRana Hi, what is the initial creation? for logout you can take a look at: https://stackoverflow.com/questions/43318310/how-to-logout-a-user-from-api-using-laravel-passport – loic.lopez Apr 09 '22 at 16:18
  • Resource Owner Password grant is deprecated as of OAuth 2.1 https://www.scottbrady91.com/oauth/why-the-resource-owner-password-credentials-grant-type-is-not-authentication-nor-suitable-for-modern-applications – Charlie Jul 21 '22 at 04:46
  • The method to generate refresh token looks good, but it gives me curl_timeout error. Can someone help please – Disha Goyal Aug 08 '22 at 20:13
  • @DishaGoyal does the command `php artisan route:list` shows the laravel passport endpoints? – loic.lopez Aug 08 '22 at 20:47
  • @loic.lopez Yes it shows me routes starting with oauth/ – Disha Goyal Aug 09 '22 at 10:45
  • Ironically if i do a post request on url http://your-app.com/oauth/token using the parameters directly in postman .. it does provides me access token and refresh token. But when i do it through code in login function it gives curl timeout error – Disha Goyal Aug 09 '22 at 10:53
2

To prevent the timeout you can call the oauth/token like this

            $request = Request::create('oauth/token', 'POST', [
                'grant_type' => 'password',
                'client_id' => env("CLIENT_ID"),
                'client_secret' => env("CLIENT_SECRET"),
                'username' => $request->email,
                'password' => $request->password,
                'scope' => '',
            ]);
            
            $result = app()->handle($request);
            $response = json_decode($result->getContent(), true); 
            return response()->json($response, 200);