Closed adaojunior closed 8 years ago
From the client side you can request for a refresh token, read this part from documentation: https://laravel.com/docs/5.3/passport#refreshing-tokens
Hi, @geodeveloper thanks,
I'm not sure if it solves the problem I have. I don't want to ask the user the insert the email and password. I want them to click on login with facebook, once it is validated (on the server) the server should create an access token + refresh token and it should probably be a Password Grant Token
instead of the Personal Access Token
that is generated from $user->createToken()
.
In that case, I guess you need to use the package Laravel Socialite (https://github.com/laravel/socialite), you don't need Laravel Passport, since this package it's only if you want to have your own OAuth2 Server.
Laravel Socialite supports login with Facebook.
I know, I'm already using Socialite, take a look in the code bellow:
public function authWithFacebook(Socialite $socialite)
{
$fields = [...];
$account = $socialite->driver('facebook')
->fields($fields)
->userFromToken(request()->get('access_token'));
$user = $this->users->findByEmail($account->getEmail());
$isNew = empty($user);
if($isNew) {
$user = $this->users->registerFromFacebook($account);
}
/// This is the missing part
return [
"token_type" => "Bearer",
"expires_in" => ...
"access_token" => ...
"refresh_token" => ...
]
}
See this: https://github.com/laravel/socialite#retrieving-user-details
So you could get that information like this:
$user = Socialite::driver('facebook')->user();
// OAuth Two Providers
$token = $user->token;
$refreshToken = $user->refreshToken; // not always provided
$expiresIn = $user->expiresIn;
// OAuth One Providers
$token = $user->token;
$tokenSecret = $user->tokenSecret;
// All Providers
$user->getId();
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();
@geodeveloper I want a token from my oauth(my server) not facebook's token.
1 - validate facebook's access_token 2 - obtain facebook user info 3 - check if user already exist, otherwise create a new user. 4 - return a access token + refresh token for this user to access my api
Then you just need to call /oauth/token on your server to get the access token and refresh token.
@adaojunior I'm looking at the same issue. I'm thinking a custom Grant needs to be created (SocialiteGrant
). If you take a look at the Laravel\Passport\Bridge\PersonalAccessGrant
, you can see how a grant is implemented. You would then need to enable the custom grant by adding it to the Laravel\Passport\PassportServiceProvider
file. Of course, you can't edit the original, so, you can create a new provider that extends that one. Then make sure to reference the new provider instead of Laravel\Passport\PassportServiceProvider
in your bootstrap.
I'm going to give it a go right now. I'll post back if I get something working.
@mikemclin thanks, that's seems like the best solution right now. let me know if you're able to implement that.
@adaojunior OK, I got it working. Half-way through I realized that limiting it to Socialite narrowed the scope. So, I made a CustomRequestGrant
.
How it works... You make a call to /oauth/token
just like you always would to get your token. But do so with a grant_type
of custom_request
. You'll need to add a byPassportCustomRequest($request)
method to your User
model (or whatever model you have configured to work with Passport). That method will accept a Illuminate\Http\Request
and return the user model if you are able to authenticate the user via the request, or it will return null
.
If a user object is returned, the request goes through and an access token and refresh token are returned. Otherwise they get an auth error response.
I need to clean it up a bit, and then I'll share...
@mikemclin are you actually making a http request ? I wonder if it is possible to simulate a http request just like it is done here https://github.com/laravel/passport/blob/master/src/PersonalAccessTokenFactory.php#L71
No, when I say new request, I am talking about transforming the existing request into a request for the oauth package, just like the example you showed. So, when I say new request, I'm referring to a new request object, not a new HTTP request.
ok, it would be nice if this would be built in into library. Maybe they will, because it is very useful and I is probably a very common use.
OK, here is the package. Pretty simple. Add the provider and then add the method to your User model. https://github.com/mikemclin/passport-custom-request-grant
@mikemclin I downloaded the package but I'm getting a "Class hash does not exist" error. Here's the stack trace:
ReflectionException in Container.php line 734: Class hash does not exist in Container.php line 734 at ReflectionClass->__construct('hash') in Container.php line 734 at Container->build('hash', array()) in Container.php line 629 at Container->make('hash', array()) in Application.php line 710 at Application->make('Illuminate\Contracts\Hashing\Hasher') in Container.php line 849 at Container->resolveClass(object(ReflectionParameter)) in Container.php line 804 at Container->getDependencies(array(object(ReflectionParameter)), array()) in Container.php line 775 at Container->build('Laravel\Passport\Bridge\UserRepository', array()) in Container.php line 629 at Container->make('Laravel\Passport\Bridge\UserRepository', array()) in Application.php line 710 at Application->make('Laravel\Passport\Bridge\UserRepository') in PassportServiceProvider.php line 138 at PassportServiceProvider->makePasswordGrant() in PassportServiceProvider.php line 80 at PassportServiceProvider->Laravel\Passport\{closure}(object(AuthorizationServer)) in helpers.php line 814 at tap(object(AuthorizationServer), object(Closure)) in PassportServiceProvider.php line 86 at PassportServiceProvider->Laravel\Passport\{closure}(object(Application), array()) in Container.php line 731 at Container->build(object(Closure), array()) in Container.php line 629 at Container->make('League\OAuth2\Server\AuthorizationServer', array()) in Application.php line 710 at Application->make('League\OAuth2\Server\AuthorizationServer', array()) in helpers.php line 106 at app('League\OAuth2\Server\AuthorizationServer') in CustomRequestGrantProvider.php line 35 at CustomRequestGrantProvider->register() in Application.php line 566 at Application->register(object(CustomRequestGrantProvider)) in ProviderRepository.php line 74 at ProviderRepository->load(array('Illuminate\Auth\AuthServiceProvider', 'Illuminate\Broadcasting\BroadcastServiceProvider', 'Illuminate\Bus\BusServiceProvider', 'Illuminate\Cache\CacheServiceProvider', 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', 'Illuminate\Cookie\CookieServiceProvider', 'Illuminate\Database\DatabaseServiceProvider', 'Illuminate\Encryption\EncryptionServiceProvider', 'Illuminate\Filesystem\FilesystemServiceProvider', 'Illuminate\Foundation\Providers\FoundationServiceProvider', 'Illuminate\Hashing\HashServiceProvider', 'Illuminate\Mail\MailServiceProvider', 'Illuminate\Notifications\NotificationServiceProvider', 'Illuminate\Pagination\PaginationServiceProvider', 'Illuminate\Pipeline\PipelineServiceProvider', 'Illuminate\Queue\QueueServiceProvider', 'Illuminate\Redis\RedisServiceProvider', 'Illuminate\Auth\Passwords\PasswordResetServiceProvider', 'Illuminate\Session\SessionServiceProvider', 'Illuminate\Translation\TranslationServiceProvider', 'Illuminate\Validation\ValidationServiceProvider', 'Illuminate\View\ViewServiceProvider', 'Laravel\Passport\PassportServiceProvider', 'MikeMcLin\Passport\CustomRequestGrantProvider', 'LogSalud\Providers\AppServiceProvider', 'LogSalud\Providers\AuthServiceProvider', 'LogSalud\Providers\EventServiceProvider', 'LogSalud\Providers\RouteServiceProvider')) in Application.php line 541 at Application->registerConfiguredProviders() in RegisterProviders.php line 17 at RegisterProviders->bootstrap(object(Application)) in Application.php line 203 at Application->bootstrapWith(array('Illuminate\Foundation\Bootstrap\DetectEnvironment', 'Illuminate\Foundation\Bootstrap\LoadConfiguration', 'Illuminate\Foundation\Bootstrap\ConfigureLogging', 'Illuminate\Foundation\Bootstrap\HandleExceptions', 'Illuminate\Foundation\Bootstrap\RegisterFacades', 'Illuminate\Foundation\Bootstrap\RegisterProviders', 'Illuminate\Foundation\Bootstrap\BootProviders')) in Kernel.php line 253 at Kernel->bootstrap() in Kernel.php line 144 at Kernel->sendRequestThroughRouter(object(Request)) in Kernel.php line 116 at Kernel->handle(object(Request)) in index.php line 54
@adrian-martinez can you submit a ticket at the project? I'd rather not hijack this issue and project with support requests for a separate project. Thanks 😄
Sure, I will. Thanks.
@themsaid is this solved ? There have been presented a solution but I believe it would be better solved in this package. Even when I first had this problem I thought I was missing something because it made so much sense that this package would handle it.
The solution here is the way to go, no plans to support custom grants out of the box at the moment :)
Hi everyone, I created a package to handle Social Login + Passport
Hi @adaojunior, good package, but can you explain how to use with Socialite ? Thanks.
@aliasdoc see SocialUserResolver
on readme:
This is what authWithFacebook
should kind of look like:
$account = Socialite::driver('facebook')
->userFromToken($accessToken);
/// Then you should probably check if the user exist on the database, otherwise create one.
/// and then return a instance of App\User
And that's it, the package takes care of the rest.
SocialUserResolver
is the only thing it requires you to code, you will receive a access token and the network you're trying to authenticate, and resolve to a App\User.
This is mostly intended to APIs, it assumes you already have the access token from the oauth provider (facebook, google, github).
@aliasdoc it is pretty much like the password grant, but instead of username/password you use the access token
provided to you.
Thank you @adaojunior but
->userFromToken($accessToken)
is not available, this method of Facebook socialite provider is protected.
Sorry @adaojunior, my version of Socialite is not updated ;). Thanks.
no problem, let me know your experience with the library.
same question, how to reponse access_token to client after user register without another extra request?
@wdd2007 Just return your local database user you either found by Facebook ID or created with it. Like @adaojunior said, the package takes care of the rest and generates an access and refresh token for that user.
Thanks for this btw, @adaojunior! Just implemented Facebook registration/login almost identical to the password grant flow.
@sebastiaanluca you're welcome
Obtaining access token, you mean getting the oauth_access_tokens? and generate the JWT?
Maybe try below code if it will work, it will grab a record using the user's token id in the table, and generates a JWT token, which is the Bearer's access_token when using postman.
$user = \Auth::user();
$token = new \Laravel\Passport\Bridge\AccessToken($user->token()->id);
$token
->setClient(new \Laravel\Passport\Bridge\Client($user->token()->id, null, null));
->setExpiryDateTime(\Carbon::now()->addYear());
$crypt_key = new \League\OAuth2\Server\CryptKey('file://'.storage_path('oauth-private.key'));
dd((string) $token->convertToJWT($crypt_key));
use Carbon\Carbon;
use Illuminate\Events\Dispatcher;
use Laravel\Passport\Bridge\AccessToken;
use Laravel\Passport\Bridge\AccessTokenRepository;
use Laravel\Passport\Bridge\Client;
use Laravel\Passport\Bridge\Scope;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\CryptKey;
$user = \Auth::user();
$token = new AccessToken($user->id);
$token->setIdentifier(generateUniqueIdentifier());
$token->setClient(new Client(2, null, null));
$token->setExpiryDateTime(Carbon::now()->addDay());
$token->addScope(new Scope('activity'));
$privateKey = new CryptKey('file://'.storage_path('oauth-private.key'));
$accessTokenRepository = new AccessTokenRepository(new TokenRepository, new Dispatcher);
$accessTokenRepository->persistNewAccessToken($token);
$jwtAccessToken = $token->convertToJWT($privateKey);
$responseParams = [
'token_type' => 'Bearer',
'expires_in' => $expireDateTime - (new \DateTime())->getTimestamp(),
'access_token' => (string) $jwtAccessToken,
'user' => $user->toArray()
];
In my case, i need login user with no password, i do it:
$user = User::find(1);
// return response
return $this->getBearerTokenByUser($user, 1, true);
// return array
return $this->getBearerTokenByUser($user, 1, false);
{
"token_type": "Bearer",
"expires_in": 3600,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEwY2MyMDZmNjc5MTViZjhkNDI1YWQ2MjUyNmQwY2NkYjE0YWU0ZWExYTcyNTgwYzNjYjFhZjVjYjlhZTQ4OWY1MzBlNDZiOTJmMTlmZjNmIn0.eyJhdWQiOiIxIiwianRpIjoiYTBjYzIwNmY2NzkxNWJmOGQ0MjVhZDYyNTI2ZDBjY2RiMTRhZTRlYTFhNzI1ODBjM2NiMWFmNWNiOWFlNDg5ZjUzMGU0NmI5MmYxOWZmM2YiLCJpYXQiOjE1MDU4MTc4ODQsIm5iZiI6MTUwNTgxNzg4NCwiZXhwIjoxNTA1ODIxNDg0LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.cBPleIiPJwnK9bazydZW4AKxBosFNZtrL-h6-K4sJ6eYZ1an5ty9g0eZNg-n3lwFuQfEVN36p__PJDnaGLvu1_5P4hB0cdQn31AAr2SOHJ5-zK7s32N3amCzn0lVGkGe-R9zPSKCKCYWU5H3JQVAD_AzD2c049T5_vOl9VCrYR4JQ2W3cdfwktztBdE9-Z0q0LAWuWLNk9Etq9zPK_CBZOVHFndInYBOlxvJJ4O9fW74LMqg8VYe3zDIn0g7l7l3ygK67MigXfQPJQjm65U4Np5Blj9js2l-o0kY4ZAI0XU1S8WAm_rnNI-0p-2Diy6ifC-22-lFTXl78WSNBREH1lH1cBYx88In03CE0P4uhP2quoHy_BFQx2P15NumtLeu8PundCt4C3OeZb0E6llOHGC1cwuXydvcdmpWrlGGEw6dcUsXtOzfH30mVI_I6_Tk2hjQNoDkVNzOSB4jHoVJ5UpeewiSH79VHOq3KwKIw4mQE3MNTf-1XeKgBhbEjmns28guATpkqqVzGh8hUZz6XXFlZie7q15HRMDnvdvWmcqsQcWB_cifmQmKNc3kFB6zgK23sCHXlHwberz6Eny8Sy3CescF5O2U0urPvyg9qPxxBq-pJ8uPVlJIPsDbUhF3gknzwCG4cSQTQbbQyjUvcrWxXhyRfIHKEmnviaxJ3Yo",
"refresh_token": "def50200b65d600ff4df3e1def9f1355f9315a1cd0d6f033006fc1d6e37d4bc61a6851d23c0f727e461e62b41392f4db18e4b577a6f7253097848840030b11f43c94403c8eecb89c8b86e5d83b48528e8ecdd3ba99fd30e3bf310260f3051e11642c274cdbce6b618eb7285c6a51c8df2b5a59794faac8a8ec8b043db11ced02dd8e008c9cc1776ced07bc62ffc95c886ecefee51f4c993965eda9308932111b910166a28a45ff6db7cbcbd6bb96ee95ef401b97cff7b64167acaa3099a0e39e47bb74a5c5384ac5f71af249f13176beb64839fdd9631988fe2bb00f32cf15deb770e88fbc60b32d89cefc1a4b2e3b5fc785400da9005e748d4b93fbb7972efaa64423a2010c62987afbd5be7b0750f9f72d354e440e8ada04daecb599955fa190e97c04f69b9a5f4e3099beef721b2ec4e2437f11e382ec6c0daeba4a843af459b66286c7f2d2ded22877ef4cac42b48a36942110af8ab5aab3a0338e6957"
}
@springjk I am using your function to create the response. I have a question about how I can decrypt the access token post receiving the same in HTTP Authorization Header
@pbalan can you give more info, i use the access_token from response no problem.
example response:
token_type=Bearer&expires_in=3600&access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijk4OTMyMWEwNmY2MTYzMjVmYzc3MzRlZGM1YzNhMmUwN2I2ZTlmOWQwNGY2YmMxMzA2ZTA4YWZmNzk3Mjk2MmU2YzBkNGM3MDIxNTdkZDMxIn0.eyJhdWQiOiIxIiwianRpIjoiOTg5MzIxYTA2ZjYxNjMyNWZjNzczNGVkYzVjM2EyZTA3YjZlOWY5ZDA0ZjZiYzEzMDZlMDhhZmY3OTcyOTYyZTZjMGQ0YzcwMjE1N2RkMzEiLCJpYXQiOjE1MDYyMjgzMDksIm5iZiI6MTUwNjIyODMwOSwiZXhwIjoxNTA2MjMxOTA5LCJzdWIiOiIyMyIsInNjb3BlcyI6W119.SN6U1QyMNXtCweswbfDQfFKKUMYI9HdRTA0EouNcVfIA1t6-OiH3TnzN206AKOFeFYOU9tzwHRLcYTwg4JHz_4jw-Bpxv2UDvTK9QEwx5uaaI_a46oebeKCz6DhoezDqaauzqJM06xBrGd2lHdqNTiYNPaXOM01oPL1n5fm9q-Ns4ybs5OR3NDeXmdYAA23XUeNmkoyTPcEglMP9ydN8IdZ8wQs4E9Nmig6g1EUR5J7YpnwUYwLVGvon9iOBjFPaArGtbYmiGPBH58wQLkWc3zOJLs5yjlKMvTBaVKZ5Fk3HE35P6rTJu6Ib8_Rd_zkwTlj646PX6aVIVfI_hXa7Yw0kQPEmfdfD61eh68U-l9jLRHhSSvszHYyFcya4hMjpjqVlG8bWhYbYQoZzTDwux_pBSmE4ZgKdnSmx6ntR5NYMVM4_bNA0NYI-5G02h0nRv4KwUYIogbJqcKj-rbeQzGz8KVrNKh55XT090jDgXrRDDwylFj-O3FnvbyYSXRSI1CXYC4zh0ian89TT5DhnpRWCuOHYYWaSlzOoiaDwYvEhuNDJ_qmpdMPcQ4CVPn9TLoAPX6ysT4FaKt2gRpiuWIbZBm1lP-LFw5qSpLShgtDN1tCPjRmo9CeLroKACHelblW3PFX-rvXwjYKzES3vozmd4GGtySHswn7YrF3UIOA&refresh_token=def50200cfc30bdc2be338bb47914499cf30bce372f9ba1fcc14c278456b072d1dd47d21283f31b9d71183560755965a4b1c39a0b7564182428e27393b2c65e61a0f2d254e6443659d218c561dda62644cf8d194c19830a1003156de50f0279860ab72cb71798587dbce2e529da52cbdc2ae6104760b168e44d4900256ff697ab412b24e098787af023865e608a409d24c6a18a464a369b3b6f20cb8f64a24d097274e912a3806990ce321ed0e26b5127f91bb242d6011ebd2e16c32a61351e9160e7cae16f3bd647c12304b0a58cadef4cd448f9f05f6141fe6caaeea4a28d666b84a1ddde452be442e43ec2965fce51e0ea9ad2ef0b1f687bb0b9b0ab59756e85b8c34f12905a67bd8cd4ba0d559d4ffaa76cb95a3313e6d8e1a5c64d0479e95a0a988bce87f0ab13c3ee5dd6675b18c7d22fa1a574b7485f40043ffbe420e08bd1a45b614e2ac35fd913688cedce72a1a4f99bad5702cf4b23823256599a9
set token to header Authorization
if you don't want use auth middleware, you should create a custom function parseToken
public function __construct()
{
parent::__construct();
$key_path = Passport::keyPath('oauth-public.key');
$this->parseTokenKey = file_get_contents($key_path);
}
private function parseToken($token)
{
$token = (new Parser())->parse((string) $token);
$signer = new Sha256();
if ($token->verify($signer, $this->parseTokenKey)) {
$user_id = $token->getClaim('sub');
$user = app(UserRepository::class)->find($user_id); // yourself logic
return $user;
} else {
return false;
}
}
@springjk i got this error
"Key file "file:///home/vagrant/www/mapaya/example/storage/oauth-private.key" permissions are not correct, should be 600 or 660 instead of 777"
I've tried change using chmod issue still exists. any solution?
@stefensuhat your issue is another question, no about this issue.
you should chown
this file owner to php-fpm user and group, like
chown www-data:www-data oauth-private.key
And this command must run in your vagrant not host computer.
You can find more information in #454 , good luck.
@stefensuhat / anyone using windows, instead of -
$privateKey = new CryptKey('file://'.Passport::keyPath('oauth-private.key'));
Use - $privateKey = new CryptKey('file://'.Passport::keyPath('oauth-private.key'), null, false);
@springjk I have a problem using your solution, I can receive a access_token
and a refresh_token
but when I try to use the token to make other calls the response is:
{
"message": "Unauthenticated."
}
Do you know why? I've search a lot but any of the "solutions" works in my case. I'm using Laravel 5.5 with Passport 4.0
@dickwu Your code works great for my use case. Thank you :) I've modified it a little bit for it to works in my User Model but it look like this now:
$token->setIdentifier(bin2hex(random_bytes(40)));
It use the same function as the generateUniqueIdentifier from AbstractGrant class.
$accessTokenRepository = new AccessTokenRepository(app('db.connection'), new Dispatcher);
and at least in 5.3 it ask for a DB connection, not the Token repository so here it is.
Thanks @springjk . Your code helped me.
I want to know if i have created access token like what you said, after token expiration how can i refresh token programmatically without making http request to oauth/token
?
Hi @Roadirsh Where definition function generateUniqueIdentifier () or what it must return? integer?
Error:
FatalThrowableError
Call to undefined function App\Http\Controllers\generateUniqueIdentifier()
@kennyhorna App/Traits/PassportToken.php (Click to expand) in up message
@pbalan can you give more info, i use the access_token from response no problem.
example response:
token_type=Bearer&expires_in=3600&access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6Ijk4OTMyMWEwNmY2MTYzMjVmYzc3MzRlZGM1YzNhMmUwN2I2ZTlmOWQwNGY2YmMxMzA2ZTA4YWZmNzk3Mjk2MmU2YzBkNGM3MDIxNTdkZDMxIn0.eyJhdWQiOiIxIiwianRpIjoiOTg5MzIxYTA2ZjYxNjMyNWZjNzczNGVkYzVjM2EyZTA3YjZlOWY5ZDA0ZjZiYzEzMDZlMDhhZmY3OTcyOTYyZTZjMGQ0YzcwMjE1N2RkMzEiLCJpYXQiOjE1MDYyMjgzMDksIm5iZiI6MTUwNjIyODMwOSwiZXhwIjoxNTA2MjMxOTA5LCJzdWIiOiIyMyIsInNjb3BlcyI6W119.SN6U1QyMNXtCweswbfDQfFKKUMYI9HdRTA0EouNcVfIA1t6-OiH3TnzN206AKOFeFYOU9tzwHRLcYTwg4JHz_4jw-Bpxv2UDvTK9QEwx5uaaI_a46oebeKCz6DhoezDqaauzqJM06xBrGd2lHdqNTiYNPaXOM01oPL1n5fm9q-Ns4ybs5OR3NDeXmdYAA23XUeNmkoyTPcEglMP9ydN8IdZ8wQs4E9Nmig6g1EUR5J7YpnwUYwLVGvon9iOBjFPaArGtbYmiGPBH58wQLkWc3zOJLs5yjlKMvTBaVKZ5Fk3HE35P6rTJu6Ib8_Rd_zkwTlj646PX6aVIVfI_hXa7Yw0kQPEmfdfD61eh68U-l9jLRHhSSvszHYyFcya4hMjpjqVlG8bWhYbYQoZzTDwux_pBSmE4ZgKdnSmx6ntR5NYMVM4_bNA0NYI-5G02h0nRv4KwUYIogbJqcKj-rbeQzGz8KVrNKh55XT090jDgXrRDDwylFj-O3FnvbyYSXRSI1CXYC4zh0ian89TT5DhnpRWCuOHYYWaSlzOoiaDwYvEhuNDJ_qmpdMPcQ4CVPn9TLoAPX6ysT4FaKt2gRpiuWIbZBm1lP-LFw5qSpLShgtDN1tCPjRmo9CeLroKACHelblW3PFX-rvXwjYKzES3vozmd4GGtySHswn7YrF3UIOA&refresh_token=def50200cfc30bdc2be338bb47914499cf30bce372f9ba1fcc14c278456b072d1dd47d21283f31b9d71183560755965a4b1c39a0b7564182428e27393b2c65e61a0f2d254e6443659d218c561dda62644cf8d194c19830a1003156de50f0279860ab72cb71798587dbce2e529da52cbdc2ae6104760b168e44d4900256ff697ab412b24e098787af023865e608a409d24c6a18a464a369b3b6f20cb8f64a24d097274e912a3806990ce321ed0e26b5127f91bb242d6011ebd2e16c32a61351e9160e7cae16f3bd647c12304b0a58cadef4cd448f9f05f6141fe6caaeea4a28d666b84a1ddde452be442e43ec2965fce51e0ea9ad2ef0b1f687bb0b9b0ab59756e85b8c34f12905a67bd8cd4ba0d559d4ffaa76cb95a3313e6d8e1a5c64d0479e95a0a988bce87f0ab13c3ee5dd6675b18c7d22fa1a574b7485f40043ffbe420e08bd1a45b614e2ac35fd913688cedce72a1a4f99bad5702cf4b23823256599a9
set token to header
Authorization
if you don't want use auth middleware, you should create a custom function
parseToken
public function __construct() { parent::__construct(); $key_path = Passport::keyPath('oauth-public.key'); $this->parseTokenKey = file_get_contents($key_path); } private function parseToken($token) { $token = (new Parser())->parse((string) $token); $signer = new Sha256(); if ($token->verify($signer, $this->parseTokenKey)) { $user_id = $token->getClaim('sub'); $user = app(UserRepository::class)->find($user_id); // yourself logic return $user; } else { return false; } }
use Lcobucci\JWT\Parser; use Lcobucci\JWT\Signer\Rsa\Sha256;
and remember to remove the Bearer+ prefix from your token .
In my case, i need login user with no password, i do it:
- create a trait
App/Traits/PassportToken.php (Click to expand)
<?php namespace App\Traits; use App\Entities\User; use DateTime; use GuzzleHttp\Psr7\Response; use Illuminate\Events\Dispatcher; use Laravel\Passport\Bridge\AccessToken; use Laravel\Passport\Bridge\AccessTokenRepository; use Laravel\Passport\Bridge\Client; use Laravel\Passport\Bridge\RefreshTokenRepository; use Laravel\Passport\Passport; use Laravel\Passport\TokenRepository; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\Entities\AccessTokenEntityInterface; use League\OAuth2\Server\Exception\OAuthServerException; use League\OAuth2\Server\Exception\UniqueTokenIdentifierConstraintViolationException; use League\OAuth2\Server\ResponseTypes\BearerTokenResponse; # https://github.com/laravel/passport/issues/71 /** * Trait PassportToken * * @package App\Traits */ trait PassportToken { /** * Generate a new unique identifier. * * @param int $length * * @throws OAuthServerException * * @return string */ private function generateUniqueIdentifier($length = 40) { try { return bin2hex(random_bytes($length)); // @codeCoverageIgnoreStart } catch (\TypeError $e) { throw OAuthServerException::serverError('An unexpected error has occurred'); } catch (\Error $e) { throw OAuthServerException::serverError('An unexpected error has occurred'); } catch (\Exception $e) { // If you get this message, the CSPRNG failed hard. throw OAuthServerException::serverError('Could not generate a random string'); } // @codeCoverageIgnoreEnd } private function issueRefreshToken(AccessTokenEntityInterface $accessToken) { $maxGenerationAttempts = 10; $refreshTokenRepository = app(RefreshTokenRepository::class); $refreshToken = $refreshTokenRepository->getNewRefreshToken(); $refreshToken->setExpiryDateTime((new \DateTime())->add(Passport::refreshTokensExpireIn())); $refreshToken->setAccessToken($accessToken); while ($maxGenerationAttempts-- > 0) { $refreshToken->setIdentifier($this->generateUniqueIdentifier()); try { $refreshTokenRepository->persistNewRefreshToken($refreshToken); return $refreshToken; } catch (UniqueTokenIdentifierConstraintViolationException $e) { if ($maxGenerationAttempts === 0) { throw $e; } } } } protected function createPassportTokenByUser(User $user, $clientId) { $accessToken = new AccessToken($user->id); $accessToken->setIdentifier($this->generateUniqueIdentifier()); $accessToken->setClient(new Client($clientId, null, null)); $accessToken->setExpiryDateTime((new DateTime())->add(Passport::tokensExpireIn())); $accessTokenRepository = new AccessTokenRepository(new TokenRepository(), new Dispatcher()); $accessTokenRepository->persistNewAccessToken($accessToken); $refreshToken = $this->issueRefreshToken($accessToken); return [ 'access_token' => $accessToken, 'refresh_token' => $refreshToken, ]; } protected function sendBearerTokenResponse($accessToken, $refreshToken) { $response = new BearerTokenResponse(); $response->setAccessToken($accessToken); $response->setRefreshToken($refreshToken); $privateKey = new CryptKey('file://'.Passport::keyPath('oauth-private.key')); $response->setPrivateKey($privateKey); $response->setEncryptionKey(app('encrypter')->getKey()); return $response->generateHttpResponse(new Response); } /** * @param \App\Entities\User $user * @param $clientId * @param bool $output default = true * @return array | \League\OAuth2\Server\ResponseTypes\BearerTokenResponse */ protected function getBearerTokenByUser(User $user, $clientId, $output = true) { $passportToken = $this->createPassportTokenByUser($user, $clientId); $bearerToken = $this->sendBearerTokenResponse($passportToken['access_token'], $passportToken['refresh_token']); if (! $output) { $bearerToken = json_decode($bearerToken->getBody()->__toString(), true); } return $bearerToken; } }
- use
$user = User::find(1); // return response return $this->getBearerTokenByUser($user, 1, true); // return array return $this->getBearerTokenByUser($user, 1, false);
- response
{ "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEwY2MyMDZmNjc5MTViZjhkNDI1YWQ2MjUyNmQwY2NkYjE0YWU0ZWExYTcyNTgwYzNjYjFhZjVjYjlhZTQ4OWY1MzBlNDZiOTJmMTlmZjNmIn0.eyJhdWQiOiIxIiwianRpIjoiYTBjYzIwNmY2NzkxNWJmOGQ0MjVhZDYyNTI2ZDBjY2RiMTRhZTRlYTFhNzI1ODBjM2NiMWFmNWNiOWFlNDg5ZjUzMGU0NmI5MmYxOWZmM2YiLCJpYXQiOjE1MDU4MTc4ODQsIm5iZiI6MTUwNTgxNzg4NCwiZXhwIjoxNTA1ODIxNDg0LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.cBPleIiPJwnK9bazydZW4AKxBosFNZtrL-h6-K4sJ6eYZ1an5ty9g0eZNg-n3lwFuQfEVN36p__PJDnaGLvu1_5P4hB0cdQn31AAr2SOHJ5-zK7s32N3amCzn0lVGkGe-R9zPSKCKCYWU5H3JQVAD_AzD2c049T5_vOl9VCrYR4JQ2W3cdfwktztBdE9-Z0q0LAWuWLNk9Etq9zPK_CBZOVHFndInYBOlxvJJ4O9fW74LMqg8VYe3zDIn0g7l7l3ygK67MigXfQPJQjm65U4Np5Blj9js2l-o0kY4ZAI0XU1S8WAm_rnNI-0p-2Diy6ifC-22-lFTXl78WSNBREH1lH1cBYx88In03CE0P4uhP2quoHy_BFQx2P15NumtLeu8PundCt4C3OeZb0E6llOHGC1cwuXydvcdmpWrlGGEw6dcUsXtOzfH30mVI_I6_Tk2hjQNoDkVNzOSB4jHoVJ5UpeewiSH79VHOq3KwKIw4mQE3MNTf-1XeKgBhbEjmns28guATpkqqVzGh8hUZz6XXFlZie7q15HRMDnvdvWmcqsQcWB_cifmQmKNc3kFB6zgK23sCHXlHwberz6Eny8Sy3CescF5O2U0urPvyg9qPxxBq-pJ8uPVlJIPsDbUhF3gknzwCG4cSQTQbbQyjUvcrWxXhyRfIHKEmnviaxJ3Yo", "refresh_token": "def50200b65d600ff4df3e1def9f1355f9315a1cd0d6f033006fc1d6e37d4bc61a6851d23c0f727e461e62b41392f4db18e4b577a6f7253097848840030b11f43c94403c8eecb89c8b86e5d83b48528e8ecdd3ba99fd30e3bf310260f3051e11642c274cdbce6b618eb7285c6a51c8df2b5a59794faac8a8ec8b043db11ced02dd8e008c9cc1776ced07bc62ffc95c886ecefee51f4c993965eda9308932111b910166a28a45ff6db7cbcbd6bb96ee95ef401b97cff7b64167acaa3099a0e39e47bb74a5c5384ac5f71af249f13176beb64839fdd9631988fe2bb00f32cf15deb770e88fbc60b32d89cefc1a4b2e3b5fc785400da9005e748d4b93fbb7972efaa64423a2010c62987afbd5be7b0750f9f72d354e440e8ada04daecb599955fa190e97c04f69b9a5f4e3099beef721b2ec4e2437f11e382ec6c0daeba4a843af459b66286c7f2d2ded22877ef4cac42b48a36942110af8ab5aab3a0338e6957" }
Thansk for this solution. Something I have been hunting from days now. Much appreciated work :D
A small doubt though,
new AccessTokenRepository(new TokenRepository(), new Dispatcher())
Here the first argument should be Database connection, as per the passport function. Could you provide more info like based on which version you developed this trait so that I can refer to changelogs from there onwards and re-create one for myself.
@farhoudi did you get any idea about refreshing token without making request to oauth/token
@jkunwar @farhoudi you shouldn't do this as it won't conform to the OAuth 2 spec. Automatically issuing new access tokens without being requested by a client feels like a security hole to me that could be exploited. I would advise you don't do this.
@Sephster Actually I used this method to customize API's input and output to integrate with my other APIs. @jkunwar Yes, I did this:
try {
$oauthClient = $this->oauthClientRepository->where('password_client', true)->first();
if (empty($oauthClient)) {
return [
'message' => trans('users.error_allocating_token'),
];
}
$params = [
'grant_type' => 'refresh_token',
'refresh_token' => $input['refresh_token'],
'client_id' => $oauthClient->id,
'client_secret' => $oauthClient->secret,
'scope' => null,
];
$request->request->add($params);
Route::post('/api/oauth/token', '\Laravel\Passport\Http\Controllers\AccessTokenController@issueToken');
$oauthRequest = Request::create('api/oauth/token', 'POST');
$response = Route::dispatch($oauthRequest);
$response = json_decode($response->getContent());
} catch (\Exception $ex) {
logger($ex->getMessage() . ' : ' . $ex->getFile() . ' : ' . $ex->getLine());
return [
'message' => trans('general.input_error'),
];
}
if (!empty($response->token_type) && !empty($response->access_token) &&
!empty($response->refresh_token) && !empty($response->expires_in)) {
return [
'success' => true,
'data' => $response,
];
}
In my case, i need login user with no password, i do it:
- create a trait
App/Traits/PassportToken.php (Click to expand)
- use
$user = User::find(1); // return response return $this->getBearerTokenByUser($user, 1, true); // return array return $this->getBearerTokenByUser($user, 1, false);
- response
{ "token_type": "Bearer", "expires_in": 3600, "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImEwY2MyMDZmNjc5MTViZjhkNDI1YWQ2MjUyNmQwY2NkYjE0YWU0ZWExYTcyNTgwYzNjYjFhZjVjYjlhZTQ4OWY1MzBlNDZiOTJmMTlmZjNmIn0.eyJhdWQiOiIxIiwianRpIjoiYTBjYzIwNmY2NzkxNWJmOGQ0MjVhZDYyNTI2ZDBjY2RiMTRhZTRlYTFhNzI1ODBjM2NiMWFmNWNiOWFlNDg5ZjUzMGU0NmI5MmYxOWZmM2YiLCJpYXQiOjE1MDU4MTc4ODQsIm5iZiI6MTUwNTgxNzg4NCwiZXhwIjoxNTA1ODIxNDg0LCJzdWIiOiIxIiwic2NvcGVzIjpbXX0.cBPleIiPJwnK9bazydZW4AKxBosFNZtrL-h6-K4sJ6eYZ1an5ty9g0eZNg-n3lwFuQfEVN36p__PJDnaGLvu1_5P4hB0cdQn31AAr2SOHJ5-zK7s32N3amCzn0lVGkGe-R9zPSKCKCYWU5H3JQVAD_AzD2c049T5_vOl9VCrYR4JQ2W3cdfwktztBdE9-Z0q0LAWuWLNk9Etq9zPK_CBZOVHFndInYBOlxvJJ4O9fW74LMqg8VYe3zDIn0g7l7l3ygK67MigXfQPJQjm65U4Np5Blj9js2l-o0kY4ZAI0XU1S8WAm_rnNI-0p-2Diy6ifC-22-lFTXl78WSNBREH1lH1cBYx88In03CE0P4uhP2quoHy_BFQx2P15NumtLeu8PundCt4C3OeZb0E6llOHGC1cwuXydvcdmpWrlGGEw6dcUsXtOzfH30mVI_I6_Tk2hjQNoDkVNzOSB4jHoVJ5UpeewiSH79VHOq3KwKIw4mQE3MNTf-1XeKgBhbEjmns28guATpkqqVzGh8hUZz6XXFlZie7q15HRMDnvdvWmcqsQcWB_cifmQmKNc3kFB6zgK23sCHXlHwberz6Eny8Sy3CescF5O2U0urPvyg9qPxxBq-pJ8uPVlJIPsDbUhF3gknzwCG4cSQTQbbQyjUvcrWxXhyRfIHKEmnviaxJ3Yo", "refresh_token": "def50200b65d600ff4df3e1def9f1355f9315a1cd0d6f033006fc1d6e37d4bc61a6851d23c0f727e461e62b41392f4db18e4b577a6f7253097848840030b11f43c94403c8eecb89c8b86e5d83b48528e8ecdd3ba99fd30e3bf310260f3051e11642c274cdbce6b618eb7285c6a51c8df2b5a59794faac8a8ec8b043db11ced02dd8e008c9cc1776ced07bc62ffc95c886ecefee51f4c993965eda9308932111b910166a28a45ff6db7cbcbd6bb96ee95ef401b97cff7b64167acaa3099a0e39e47bb74a5c5384ac5f71af249f13176beb64839fdd9631988fe2bb00f32cf15deb770e88fbc60b32d89cefc1a4b2e3b5fc785400da9005e748d4b93fbb7972efaa64423a2010c62987afbd5be7b0750f9f72d354e440e8ada04daecb599955fa190e97c04f69b9a5f4e3099beef721b2ec4e2437f11e382ec6c0daeba4a843af459b66286c7f2d2ded22877ef4cac42b48a36942110af8ab5aab3a0338e6957" }
This solution is perfect for Laravel <=5.7, I've been using this for a while now, thanks for sharing!
However, for Laravel 5.8 it won't work because Illuminate/Events/Dispatcher class has been removed. Could you also share a solution?
@davidnoguerol 请问您找到5.8的解决方案了吗?谢谢
Sorry for asking a question here, but I tried elsewhere and no one could answer.
Let's say I have a mobile app in which the user can login with Facebook. If it was on the web, after the authorization I would have this:
auth()->login($user);
but I'm not sure how to do this with Passport.The use does have a
createToken()
method, but how do I get the refresh token so I can have a reponse like this?