passport: API Authentication Error: {"error":"invalid_client","message":"Client authentication failed"}

I followed the exact steps mentioned in the Laracast: What’s New in Laravel 5.3: Laravel Passport and API Authentication (Passport) to implement API Authentication using Oauth2.

consumer/routes/web.php

Route::get('/redirect', function () {
    $query = http_build_query([
        'client_id' => '3',
        'redirect_uri' => 'http://consumer.dev/callback',
        'response_type' => 'code',
        'scope' => '',
    ]);

    return redirect('http://passport.dev/oauth/authorize?'.$query);
});
Route::get('/callback', function (Request $request) {
    $http = new GuzzleHttp\Client;

    $response = $http->post('http://passport.dev/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => '3',
            'client_secret' => '3TfJGj4rrvOQvjZkI8dDqx78ouH99F2DuIMKHoKH',
            'redirect_uri' => 'http://consumer.dev/callback',
            'code' => $request->code,
        ],
    ]);

    return json_decode((string) $response->getBody(), true);
});

When I try to access http://consumer.dev/redirect, I get this error:

ClientException in RequestException.php line 111:
Client error: `POST http://passport.dev/oauth/token` resulted in a `401 Unauthorized` response:
{"error":"invalid_client","message":"Client authentication failed"}

How to resolve this? Thank you for your help!

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 35
  • Comments: 51 (3 by maintainers)

Most upvoted comments

@taitrongnguyen107 In your oauth_clients table, do the values you have above exist exactly as you have them in your database?

oauth_clients

id - 3
secret - 3TfJGj4rrvOQvjZkI8dDqx78ouH99F2DuIMKHoKH
redirect - http://consumer.dev/callback

If it doesn’t exist exactly like that in the database for passport.dev then it will throw the invalid_client error. Please be sure to check that and we will see if any further investigation is needed.

make sure personal_access_client and password_client field are both 0 in table oauth_clients

Finally, I know the reason… If you wanna get the Authorization Codes, you must use the following command to generate the client…

php artisan passport:client

Then you will be redirected For Authorization successfully~ Try to compare the data in their tables, you will know the reason. And you could keep on going!!!

I experienced this issue because my “redirect_uri” did not match what was in my oauth_clients table. Changing to the below code allowed me to generate the token:

public function callback(Request $request)
    {
        $http = new \GuzzleHttp\Client;

        $params = [
            'form_params' => [
                'grant_type' => 'authorization_code',
                'client_id' => $this->oauth_client_id,
                'client_secret' => $this->oauth_client_secret,
                'redirect_uri' => url('/callback'),
                'code' => $request->code,
            ],
        ];

        $response = $http->post($this->oauth_service_url.'/oauth/token', $params);

        return json_decode((string) $response->getBody(), true);
    }

@Sphinxs Check that oauth_clients.password field is set to 1. In Passport, password grant type is a special grant type that must be opted into:

php artisan passport:client --password

https://laravel.com/docs/5.6/passport#password-grant-tokens

I’ve solved the issue by

  1. running

php artisan passport:install

  1. making sure that the client_id and secret pass is exactly the same in the database
  2. making sure that the client_id in your consumer app has quote. ‘1’.
  3. I also update my passport to 2.0.6, (not sure if this matter, but i’m including it anyway),

composer require laravel/passport “2.0.6”

below is my code.

Route::get('/redirect', function () {
    $query = http_build_query([
        'client_id' => '1',
        'redirect_uri' => 'http://client.dev/callback',
        'response_type' => 'code',
        'scope' => ''
    ]);
    return redirect('http://tickettit.dev/oauth/authorize?'.$query);
});

Route::get('/callback', function (Illuminate\Http\Request $request) {
    $http = new \GuzzleHttp\Client;

    $response = $http->post('http://tickettit.dev/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => '1',
            'client_secret' => 'euwSLAk4UjkaYtKPlQuotL2v5nbyX8qUvGpEnQ49',
             'redirect_uri' => 'http://client.dev/callback',
            'code' => $request->code,
        ],
    ]);
    return json_decode((string) $response->getBody(), true);
});



Like @taitrongnguyen107 , I have been stuck to the same issue. Having followed the same tutorials.

I can make a /request call to passport.dev from consumer.dev. but when I click Approve It redirects to the callback route gives me the exact same error given in the issue title.

I am using passport v2.0.4. Laravel Framework version 5.4.15.

Any help would be appreciated.

@taitrongnguyen107 Ok, so I just went through the instructions and everything worked out perfectly. That leads me to believe it might be the version of Passport you have installed or the environment in which you are working. Before I post the code and data I had available for this test, I am using Homestead and have the latest version of Passport installed at the time of writing (1.0.17). So this was the process I followed, perhaps it might show something you may have missed.

I set up two different new Laravel projects and they can be accessed at provider.dev and consumer.dev. They have two separate databases, provider and consumer. In the provider project, I installed Passport with composer require laravel/passport. The next step was to add the service provider and run migrate the database. After that I ran the php artisan passport:install command to generate the private keys and two entries in the oauth_clients table. Next I added the HasApiTokens trait to your User model. Then I added the Passport::routes() call to the AuthServiceProvider and changed the api guard driver from token to passport in config/auth.php. Then I ran the php artisan make:auth command to scaffold out a login system for the provider as this flow requires an authenticated user. Lastly, I created a user in tinker with the default factory provided by Laravel.

Next I moved onto the consumer project. The first needed is to install Guzzle using composer require guzzlehttp/guzzle. Next I added the two routes with the following code.

Route::get('/redirect', function () {
    $query = http_build_query([
        'client_id' => '3',
        'redirect_uri' => 'http://consumer.dev/callback',
        'response_type' => 'code',
        'scope' => '',
    ]);

    return redirect('http://provider.dev/oauth/authorize?'.$query);
});

Route::get('/callback', function (\Illuminate\Http\Request $request) {
    $http = new GuzzleHttp\Client;

    $response = $http->post('http://provider.dev/oauth/token', [
        'form_params' => [
            'grant_type' => 'authorization_code',
            'client_id' => '3',
            'client_secret' => 'OpJbevU3wMcZSMk6PNYLkKe1DmnUctWHTEyTuLME',
            'redirect_uri' => 'http://consumer.dev/callback',
            'code' => $request->code,
        ],
    ]);

    return json_decode((string) $response->getBody(), true);
});

With that, all of the coding necessary is done. When I visit http://consumer.dev/redirect I get sent to http://provider.dev/oauth/authorize (with the query string of course). Assuming I am not logged into provider.dev I will get sent to the /login page. After I login with the fake user I created earlier I get redirected back where I can either approve or deny the request. Assuming I approve it I will get redirected back to http://consumer.dev/callback with a code query parameter that will trigger the POST request to http://provider.dev/oauth/token and return the access_token and refresh_token.

Just for completeness sake, if you deny the request, guzzle will throw a ClientException that returns the following error from Passport.

{
  "error":"invalid_request",
  "message":"The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
  "hint":"Check the `code` parameter"
}

Lastly this is exactly what the oauth_client that was used looks like in the database.

| id | user_id | name        | secret                                   | redirect                     | personal_access_client | password_client | revoked | created_at          | updated_at          |
|----|---------|-------------|------------------------------------------|------------------------------|------------------------|-----------------|---------|---------------------|---------------------|
| 3  | 1       | Test Client | OpJbevU3wMcZSMk6PNYLkKe1DmnUctWHTEyTuLME | http://consumer.dev/callback | 0                      | 0               | 0       | 2016-12-31 16:07:54 | 2016-12-31 16:07:54 |

All that being said, I don’t see a single reason besides the Passport version or your environment to be causing the problem, assuming your code and process matches up. Let me know if you see any discrepancies between your process and mine.

if you are not using the default name [Laravel Password Grant Client] please not it down and provide it during testing, i would recommend using blank if you are not sure what you you are doing. Do a php artisan migrate:rollback then php artisan migrate again, then perform a php artisan passport:keys to generate keys then lastly php artisan passport:client --password. Don’t type anything, press enter and let laravel generate the password. you should stop experiencing the error

I have the same problem but when I sent requests using Postman the same code works fine. I think the problem is, the sender and receiver both are on the localhost that is causing the problem. Otherwise there is nothing wrong in the Laravel Passport documentation or Passport version.

Another possible solution would be to check that you have your JSON configured properly. I have typed ‘client_passsword’ instead of ‘client_secret’.

I’ve solved the problem by

php artisan serve --port=8000 (for provider.dev) php artisan serve --port=8080 (for consumer.dev)

Set redirect url http://localhost:8080/callback for oauth client Don’t forget set URL’s in .env localhost:8000 for provider / localhost:8080 for consumer…

If you want servers on LAN type php artisan serve --host=192.168.?.? --port=8080 (or 8000)

Also it happens when your dev and consume site hosted locally. It is related to env variables. So you you can try paste APP_KEY value from .env file as value for config/app.php ‘key’ like this ‘key’ => “base64:l84hvor2nIytcH2BpmjWsaatLOp5hY5o9fAGEuTrYPk=”, instead of ‘key’ => env(‘APP_KEY’),

Please note that you will start receiving “invalid_request” errors automatically if upgrading to php 7.3 and switching off emulated prepares on PDO. See the discussion at thephpleague/oauth2-server#1054 for reference.

I finally figured out what was the problem. If you pass your cliend_id as a number like I was doing as shown below:

{
    client_id: 3,
    redirect_uri: 'http://localhost:3000/oauth',
    response_type: 'code',
    scope: '*',
    client_secret: '5555555555555'
}

It will fail in one of Laravel`s Passport validations as you can see through this link. So in order to get it working, I only needed to add singlee (or double) quotes like this:

{
    client_id: '3',
    redirect_uri: 'http://localhost:3000/oauth',
    response_type: 'code',
    scope: '*',
    client_secret: '5555555555555'
}

Oh gosh I spent 3 days to found out it was just about missing quotes. :v

please check your redirect uri as same as the url(redirect) in the table(oauth_clients),create a new client and check again,it,s work for me.

 $query = http_build_query([
        'client_id' => '6',
        'redirect_uri' => 'http://127.0.1.7/callback',
        'response_type' => 'code',
        'scope' => '',
    ]);