I'm new to API world.
In my mind and based on internet research, I guess this is how basic API authentication works (please correct me if I'm wrong):
Basically, I want to achieve exact above thing.
But as far as I know in Oauth2, you need to create a client on the API server to get the client id and client secret. And then you have to send those two along with other parameters in the request.
What I don't understand is the request parameters to get an access token:
https://laravel.com/docs/master/passport#password-grant-tokens
$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => '[email protected]',
'password' => 'my-password',
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
I thought to just get an access token just email/username and password are enough parameters. So I'm confused about the extra parameters in the above request.
Do I have to first create a client on API server to get client_id and client_secret and then need to send them in the login request?
Do I need to create a separate client(client_id and client_secret) for each and every users of the app?
I read the entire doc but I didn't get that how can I use it to achieve what I want. I also read about the Oauth2 but it is a bit complicated for me.
Any help would be appreciated.
Thanks
If you ran the artisan command php artisan passport:install per the docs you should have already gotten two clients. You will find the id and secrets in the database for the entry that says password_client = 1. For me I don't use passport as a multi client auth server (yet) so I only need one client. I made a seeder that inserts the only password client I need (instead of running the artisan passport:install command).
$client = ClientModel::find(1);
if (!$client) {
$client = new ClientModel();
}
$client->id = 1;
$client->name = "Password Grant Client";
$client->user_id = null;
$client->secret = '';
$client->redirect = '';
$client->personal_access_client = 0;
$client->password_client = 1;
$client->revoked = 0;
$client->save();
Then I have a middleware that I put in front of my custom authenticate route that fills in the oauth parameters automatically.
public function handle($request, \Closure $next)
{
$convenienceData = [
'grant_type' => 'password',
'client_id' => 1,
'client_secret' => '',
'username' => $request->input('email'),
];
$request->merge($convenienceData);
$response = $next($request);
return $response;
}
And lastly my custom endpoint controller just extends AccessTokenController
class OauthController extends AccessTokenController
{
public function oauthHandle(ServerRequestInterface $request)
{
$resp = $this->issueToken($request);
// you can do other custom logic here
return $resp;
}
}
xparthx I was able to get access_token and use it after sending from angular
let data = {
"grant_type": "password",
"client_id": "2",
"client_secret": "MToEmN4nw7j4kqeMmzqPsM1MnyxDaQZdFAlh3akA",
"username": "[email protected]",
"password": "123456",
"scope": "*"
};
return new Promise(resolve => {
this.http.post(this.baseUrl + "/oauth/token", data, headers)
.subscribe(res => resolve(res.json()));
});
Maybe you can explain me where you store it for reuse in mobile app, or how you can reuse that token at a later time !?
Or if we will generate that tokens for 10 minutes life, than we have to put a cron to clean up older tokens ?
I solved this issue by using passports implicit grant token. Refer to documentation here
For those looking to bypass the full OAuth2 authentication flow and in situations where the client credentials cannot be securely stored, such as a mobile application, implicit grant tokens are best used
When i want all user only send username and password, you can try this:
use Laravel\Passport\Http\Controllers\AccessTokenController;
class SimpleController extends AccessTokenController
{
/*
.
.
.
*/
/**
* @param ServerRequestInterface|\Zend\Diactoros\ServerRequest $request
* @return \Illuminate\Http\Response
*/
public function simpleIssueToken(ServerRequestInterface $request)
{
$getBody = $request->getParsedBody();
$newBody = array_merge([
'grant_type' => "password",
'client_id' => 1,
'client_secret' => "secret",
'scope' => '*'
], $getBody);
$newRequest = $request->withParsedBody($newBody);
return parent::issueToken($newRequest);
}
}
Is quite similar like rickshawhobo's solution
@rickshawhobo Is that the right way of doing it though? I need to implement this for Laravel/ Mobile app project, where mobile app users will be clients (one per user) and Laravel app is a server. Since I can't save client_id and client_secret anywhere on the mobile (security reasons and reset password reasons) I had to create a middleware which intercepts requests, looks up username in the oauth_clients database, fetches the client_id and client_secret and replaces it in the request, then passes it on.
Is there an easier way of implementing api login from mobile apps via Passport?
You'll have to send along the client_id and client_secret to passport can identify the client which you're sending your auth requests to.
Note: It is no longer best practice to use the Implicit Grant. Industry best practice recommends using the Authorization Code Grant with PKCE (Proof Key For Code Exchange) for native and browser-based apps.
I found this helpful: https://oauth2.thephpleague.com/authorization-server/which-grant/
and also: https://laravel.com/docs/6.x/passport#code-grant-pkce
Most helpful comment
If you ran the artisan command
php artisan passport:installper the docs you should have already gotten two clients. You will find the id and secrets in the database for the entry that says password_client = 1. For me I don't use passport as a multi client auth server (yet) so I only need one client. I made a seeder that inserts the only password client I need (instead of running the artisan passport:install command).Then I have a middleware that I put in front of my custom authenticate route that fills in the oauth parameters automatically.
And lastly my custom endpoint controller just extends
AccessTokenController