Laravel 8 / Passport not working - Client authentication failed in Postman tests

Viewed 1189

I am using fresh install of Laravel 8 and passport to create oauth2 server. To test with the client I use Postman. Following this guide https://laravel.com/docs/8.x/passport#introduction here are all the changes I've made:

AuthServiceProvider.php:

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
         'App\Models\Model' => 'App\Policies\ModelPolicy',
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        //
        if (! $this->app->routesAreCached()) {
            Passport::routes();
        }

        Passport::loadKeysFrom(__DIR__.'/../secrets/oauth');

        Passport::tokensExpireIn(now()->addDays(15));
        Passport::refreshTokensExpireIn(now()->addDays(30));
        Passport::personalAccessTokensExpireIn(now()->addMonths(6));
    }
}

Here is the function responsible for the login:

public function store(LoginRequest $request)
{
    $validator = Validator::make($request->all(), [
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if ($validator->passes()) {
        $credentials = array(
            'email' => $request->email,
            'password' => hash('sha512', $request->password)
        );

        if (User::where($credentials)->exists()) {
            $user = User::where($credentials)->first();
            Auth::login($user, isset($request->remember));
            if (isset($request->query()['return_to'])) {
                return redirect($request->query()['return_to']);
            } else {
                return redirect()->intended(RouteServiceProvider::HOME);
            }
        } else {
            return redirect()->route('login');
        }
    } else {
        return redirect()->route('login', ['error' => $validator->errors()->first()]);
    }

/*

    $request->authenticate();

    $request->session()->regenerate();

    return redirect()->intended(RouteServiceProvider::HOME);*/
}

My config/auth.php:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | Supported: "session"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'users',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Resetting Passwords
    |--------------------------------------------------------------------------
    |
    | You may specify multiple password reset configurations if you have more
    | than one user table or model in the application and you want to have
    | separate password reset settings based on the specific user types.
    |
    | The expire time is the number of minutes that the reset token should be
    | considered valid. This security feature keeps tokens short-lived so
    | they have less time to be guessed. You may change this as needed.
    |
    */

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Password Confirmation Timeout
    |--------------------------------------------------------------------------
    |
    | Here you may define the amount of seconds before a password confirmation
    | times out and the user is prompted to re-enter their password via the
    | confirmation screen. By default, the timeout lasts for three hours.
    |
    */

    'password_timeout' => 10800,

];

This is my User.php model:

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var string[]
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Because it's all development let me share my secret and client ids:

enter image description here

Than here are my Postman requests:

When I execute the following link:

http://127.0.0.1:10000/oauth/authorize?client_id=2&redirect_uri=http://127.0.0.1:8000/authorize/response&response_type=code&scope&state=asdadasdasasfafasadas

This sends me to a login page where I do successful login and I get redirected to:

http://127.0.0.1:8000/authorize/response?code=def502004c696cf8720f807b6dd488df865f6a76ace0a7793f09ad6cbc6799f3e7028863bf59d8e681263c99663b5222ad71dd4ed7e8ec7e0111281409ba46d5a885ab849dd578a76ea49c755ad403b9072eb75e3d341d9d1a0b017afa1d446f92fa05e593698df39230fee2eafc1e6ff9461216c56c7e2d516748c370cd619e70f7eb426a13b03609b79fa7f7f40c7581057ec8373700a54049696fea00a3f51fcef2583ea0b6f07c873a962f19e1c50367caea0922ba5f919f7853e2bb114ba8ca6192d009fcde38ff620e0d769dda66ff1bdd8f7b5180e6d9205401f8154c99bb777a41d07f27d150390084e5ced4d4ebb57a64950d09a9a4c7bc3fff1c49d8adcf628b506d08ceae122ff32eacfb540b310483d507db9af3f448e7f93b60b35238c34093adcb9807712ccd0a65f2b1dc38621e372df33182b87655f6f78339d8d3a6cc8c63f31bf6f6888c4c98a76efb6f9ce09803b292e95b7bf71ac8f931a9f1615fdba8fa4374&state=asdadasdasasfafasadas

Than I do this request in Postman:

enter image description here

As you can see I am using the code given from the above last link. Here it is in whole:

def502004c696cf8720f807b6dd488df865f6a76ace0a7793f09ad6cbc6799f3e7028863bf59d8e681263c99663b5222ad71dd4ed7e8ec7e0111281409ba46d5a885ab849dd578a76ea49c755ad403b9072eb75e3d341d9d1a0b017afa1d446f92fa05e593698df39230fee2eafc1e6ff9461216c56c7e2d516748c370cd619e70f7eb426a13b03609b79fa7f7f40c7581057ec8373700a54049696fea00a3f51fcef2583ea0b6f07c873a962f19e1c50367caea0922ba5f919f7853e2bb114ba8ca6192d009fcde38ff620e0d769dda66ff1bdd8f7b5180e6d9205401f8154c99bb777a41d07f27d150390084e5ced4d4ebb57a64950d09a9a4c7bc3fff1c49d8adcf628b506d08ceae122ff32eacfb540b310483d507db9af3f448e7f93b60b35238c34093adcb9807712ccd0a65f2b1dc38621e372df33182b87655f6f78339d8d3a6cc8c63f31bf6f6888c4c98a76efb6f9ce09803b292e95b7bf71ac8f931a9f1615fdba8fa4374

However I receive the following error as you can see in the above screenshot:

{
    "error": "invalid_client",
    "error_description": "Client authentication failed",
    "message": "Client authentication failed"
}

Why do I receive this error? How can I fix it. As you can see I am sending correct information but nonetheless I get and error, why ?

1 Answers

The values for token generation should be passed under x-www-form-urmencoded section and there the following values should be passed:

redirect_uri
grant_type
code

Under the Header section, following should be passed:

Authorization

The value for this would be:

Basic <base 64 encoded value for clientid:client secret>

The encoded value can be generated from: https://www.base64encode.org or you may generate it using code.

Related