Blues Clues
Blues Clues

Reputation: 1848

Unauthorized 401 error in laravel 6 passport

I'm trying to use the laravel passport to authenticate users. I followed every step in laravel passport documentation. But it shows error when I access a route that is protected by 'auth:api' middleware. I've searched over the internet but any of the answers are not working so far. Please see the code, and what I've tried so far below.

Tech used

Tried so far:

routes/api.php

Route::middleware('auth:api')->group(function() {
    Route::get('user', function() {
        return request()->user();
    });

    Route::get('posts', 'PostController@index')->name('posts');
    Route::post('posts/store', 'PostController@store')->name('posts.store');
    Route::get('posts/{id}/show')->name('posts.show');

    Route::get('users/{id}/show')->name('users.show');
});

Axios

mounted() {
   axios.get('/api/posts')
      .then(res => this.posts = res.data).catch(error => console.log('Unable to fetch posts.'))
}

Error

Headers:

enter image description here

Please let me know if you need some details that is not indicated on my post yet.

Setup

  1. Run composer require laravel/passport:9 for the installation.
  2. Run php artisan migrate for the tables.
  3. Run php artisan passport:install to generate the encryption keys.
  4. Added Laravel\Passport\HasApiTokens trait in User model.
  5. Added Passport::routes(); in AuthServiceProvider.
  6. Changed guard's api driver to passport in config/auth.php.

Full source code:

Click this link

Upvotes: 3

Views: 3485

Answers (4)

I think you should review your code with the following steps.

Step 1: User model has to use HasApiTokens

...
class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

Step 2: Passport::routes method within the boot method of your AuthServiceProvider

class AuthServiceProvider extends ServiceProvider
{
...
    public function boot()
    {
        $this->registerPolicies();

        Passport::routes();
    }
}

Step 3: In your config/auth.php configuration file, you should set the driver option of the api authentication guard to passport

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

Step 4 (Optional): If you want to consume your API from your JavaScript application, you need to manually send an access token to the application and pass it with each request to your application. However, Passport includes a middleware that can handle this for you. All you need to do is add the CreateFreshApiToken middleware to your web middleware group in your app/Http/Kernel.php file:

'web' => [
    // Other middleware...
    \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
],

! You should ensure that the CreateFreshApiToken middleware is the last middleware listed in your middleware stack.

Edit (2021/10/17):
You should try to add the auth middleware to $middlewareGroups of your Kernel.php

protected $middlewareGroups = [
...
  'api' => [
    'throttle:60,1',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'auth:api', //Need to add
  ],
];

Edit (2021/10/25):
I downloaded your code and debug it. When you debug it, you will get the following result:

enter image description here

Header JWT is not valid for JSON structure. There seems to be an incompatibility between the Laravel Passport library and your system. You should check your system version (PHP, Laravel, etc). I will continue to investigate. If you have any new information, please let me know

Edit (2021/11/02):

Update your laravel/framework dependency to ^6.0 in your composer.json file. If installed, update your laravel/passport dependency to ^9.3.2 in your composer.json file.

https://laravel.com/docs/6.x/upgrade#updating-dependencies

According to Laravel 6.x documentation, the version of Laravel Passport is from 9.3.2. Please try this version.

Upvotes: 4

Martin Zeitler
Martin Zeitler

Reputation: 76679

You've forgotten to run php artisan passport:keys ...so there may be no RSA key-pair available, which is crucial. Clients usually can be added with: php artisan passport:client. And generally speaking, there is no default recipe for debugging Laravel middleware ...there only is xdebug.

Upvotes: 0

AidOnline01
AidOnline01

Reputation: 737

You should add token bearer into your ajax requests. You can get it after successful login.

// laravel
use Illuminate\Support\Facades\Auth;
use App\Models\User;

public function login()
{
    $credentials = request(['email', 'password']);
    $user = User::where('email', $credentials['email'])->first();

    if (!$user || !$token = Auth::attempt($credentials)) {
        return response()->json(['success'=> false, 'error' => 'неверный логин или пароль', 'cr' => $credentials], 422);
    }

    return $this->respondWithToken($token);
}

// vue login
async function login(email, password) {
  try {
    const response = await axios.post('/auth/login', {email, password});
    
    const token = response.data.token;
    
    // some func to store token, I am using vuex mutations for this
    storeToken(token);
  }
  catch(error) {
    console.error(error);
  }
};

// vue regular function
async function changePassword(newPassword) {
  // get token from global storage, with vuex it will be like store.state.auth.token
  const token = getToken();

  await axios.post('/user/changePassword', {newPassword}, headers: { Authorization: `Bearer ${token}`});
}

Upvotes: 0

Foramkumar Patel
Foramkumar Patel

Reputation: 309

If you are using Api/oauth prefix AND add the auth:api middleware than you need to authenticate via Bearer tokens.

So it may be you have csrf token related issue so try below to disable it.

Passport::ignoreCsrfToken(true);

Upvotes: 0

Related Questions