After hearing a lot about laravel passport, i thought of implementing it into my new project where my requirement is to create an API that'll be used in a mobile app.
So my mobile app is a client
, which will further have its users.
I followed the steps mentioned by Taylor and also read about it here. In a nutshell I followed these steps:
laravel/passport
.php artisan passport:install
client_id
and client_secret
using php artisan passport:client
redirection
and callback
routes in web.php
Then I tried calling api/user
( with Header Authorization
containing value Bearer eyJ0eXAiOiJKV1...(token)
I received the data. Pretty simple and neat.
But my app users won't have these details. So I thought of configuring Password Grant Tokens which fits perfectly in my requirement.
Now starts the real headache. I've been trying to set this up for the last 3 days and continuously getting
{"error":"invalid_client","message":"Client authentication failed"}
I've tried almost every guide I followed online: Redirection Issues, Add Atleast One Scope Solution, P100Y Issue etc.
But I'm still getting invalid client
error. Here's what I'm passing through POSTMAN to oauth/token
:
{
"grant_type": "password,"
"client_id": "3,"
"client_secret": "8BUPCSyYEdsgtZFnD6bFG6eg7MKuuKJHLsdW0k6g,"
"username": "[email protected],"
"password": "123456,"
"scope": ""
}
Any help would be appreciated.
Laravel Passport is an easy way to set up an authentication system for your API. As a Laravel package, it uses an OAuth2 server to perform authentication, creating tokens for user applications that request to interface with the API it protects, and only granting them access if their tokens are validated.
If you don't want to use the Passport middleware in the project where you want to validate the tokens, you would have to create an endpoint in the Laravel Passport server that can accept the token, perform the usual Passport validation and return a response to your service.
Laravel Passport is an OAuth 2.0 server implementation for API authentication using Laravel. Since tokens are generally used in API authentication, Laravel Passport provides an easy and secure way to implement token authorization on an OAuth 2.0 server.
Laravel Passport provides a full OAuth2 server implementation for your Laravel application in a matter of minutes. Passport is built on top of the League OAuth2 server that is maintained by Andy Millington and Simon Hamp. This documentation assumes you are already familiar with OAuth2.
Check your credentials first if they are correct, Secondly check your model table which uses \Laravel\Passport\HasApiTokens
trait that whether it contains email
column, because by default it is used to identify user when validating credentials. if your table has username
column or any other column which is used in validating credentials you must define a function findForPassport
in that model. like this,
public function findForPassport($username) {
return self::where('username', $username)->first(); // change column name whatever you use in credentials
}
I use username and password column to validate a user,
in {project_directory}\vendor\laravel\passport\src\Bridge\UserRepository.php
this function validates your credentials,
public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
{
if (is_null($model = config('auth.providers.users.model'))) {
throw new RuntimeException('Unable to determine user model from configuration.');
}
if (method_exists($model, 'findForPassport')) { // if you define the method in that model it will grab it from there other wise use email as key
$user = (new $model)->findForPassport($username);
} else {
$user = (new $model)->where('email', $username)->first();
}
if (! $user || ! $this->hasher->check($password, $user->password)) {
return;
}
return new User($user->getAuthIdentifier());
}
notice the second if statement and you will get to know what is happening there.
hope this help :)
This might help point you in the right direction because we're implementing the password grant ourselves.
1 - On your step 4 instead of running this:
php artisan passport:install
run the following to create your password grant Client:
php artisan passport:client --password
The above command will give a followup question to set the name of your Password Grant Client. Be sure to get the id and secret of this new record in your database.
2 - Your POSTMAN Post request object should be wrapped inside an object similar to the following:
'form_params' => [
'grant_type' => 'password',
'client_id' => 'my_client-id',
'client_secret' => 'my_client-secret',
'username' => 'username or email', <-pass through variables or something
'password' => 'my-user-password', <- pass through variables or something
'scope' => '',
],
Update 1 10/12/2016:
On further investigation of this issue I ran into the exact same spot you're at and was forced to dive into the rabbit hole of passport.
Currently from what I'm seeing the system has set the client identifier as 'authorization_code' when it needs to be 'password'. I'm researching how to resolve this issue you're having as I've ran into it too. I will post code to help people follow along where I've been and what I've been doing but it's 2:40 am right now so I need some sleep.
Update 2 10/12/2016
Been debugging the issue for 7 hours now. There is a method within passport that validates the client. This method takes the inputs you've added in the object (mentioned above) and attempts to get the Client Entity through a client repository class based on what you've passed in. If a Client is found it will then be checked to see if an instance of the Client Entity truly exists within the Client Entity Interface which LOOKS like it pulls in the Client's credentials from the database. However, there is a block of code which returns NULL From what I'm getting in my testing. ALL fields are being introduced properly so far but there seems to be a mix-up between the repository and the interface. Which is causing the error to be thrown.
In the end I feel I'm getting close to solving this issue. Your patience is greatly appreciated. =)
Update 3 10/12/2016
After a long period of debugging I've found the initial problem. There were fields that weren't matching up. In short, it's a setup issue.
SO
The solution in this case is:
DOUBLE CHECK ALL FIELDS In the database with ALL credentials being passed in. Right down to periods, dashes, spaces passwords, client id, client secret, VALID redirect URIs/URLs, grant_types, and scopes (if you're using them):
Make sure the client in the database has an ENUM of 1 under the "password_client" column, if not you need to create one using the mentioned php artisan command above, which I'll reference here:
php artisan passport:client --password
Make sure the secret you're passing in matches what is listed for that client in your database character for character
Make sure the id you're passing matches and is of an integer data type.
Make sure there is a name of some sort for the client
Do not worry about the user_id column when using password grants
make sure the route is correct
Make sure the email your entering in (username) is an actual user inside of your users table within your database (or whatever table you customized the laravel 5.3 system to accept as your users table, I will add a link on how to customize laravel 5.3 system to accept a different users table as default if any need it).
Make sure the grant_type is spelled correctly
Make sure you're set up to accept the response bearer token (meaning the access_token and refresh_token).
Other than that, the initial steps I've outlined in the above part of this Answer should put you back on the right track. There are others here who did mention some similar steps that are helpful but address the same error that is related to a seperate issue as well (which I'm sure is a result of a setup issue related to their specific system setup).
I hope this helps though.
Have yo try running php artisan config:cache
after all the passport commands.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With