Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

meredevelopment's avatar

Consuming API with JS and Passport, error 401 on most basic example

I have a very basic fresh Laravel 6 install, and I'm trying to 'consume' one API endpoint using the method described here: https://laravel.com/docs/6.x/passport#consuming-your-api-with-javascript

  • Passport::routes(); added to AuthServiceProvider.php
  • \Laravel\Passport\Http\Middleware\CreateFreshApiToken::class, is in Kernel.php.
  • Passport has been installed and successfully and I can access my endpoint via Postman by providing a Personal Access Token (Bearer).

My api.php routes look like this:

Route::group(['middleware' => 'auth:api'], function () {
    Route::post('posts', 'PostController@store');
    Route::get('posts', 'PostController@get');
    Route::delete('posts/{id}', 'PostController@delete');
});

My vue component (based on this tutorial for a quickstart test) attempts to access the api thus:

axios.get('/api/posts')
    .then(res => {
        commit('FETCH_POSTS', res.data)
    }).catch(err => {
    console.log(err)
})

When I check the XHR console logs in browser I see this: XHR - GET http://localhost:8000/api/posts - [HTTP/1.1 401 Unauthorized 1331ms]

If I look at the Request cookies I see:

laravel_token	"eyJpdiI6IkZjUCtGOHppT2MxU3hmXC9Jd1wvYndMZz09IiwidmFsdWUiOiJXRTNoNzh4UW9CM2NSaGV1TTRLNWs0WkxwM2dZSGJTS0U0T3NXOFBMS2JISUlJblVJSTlIdGt3eHVFam1yWDBuRkdrXC9rVyt2U0NMNGRSM0dGdU5UblZweFZcL0VlZ2RzTFwvYTVYb0orNXhYWnFHdG90OXVJMFdxZWRhWXZORUJ3a2FWMjk5VHdlVUpcL3o5SjZmc1BLS2xzVjRCN2QxQWZ2THRwbnVJbmMyNjVIUmlZdWNGZ2d0MldjbUYyYzA2a1wvN0FJbDNXUXRSSHRNeUZwSFhaQXNNamNsMndGRFlCazJoME04bmM2R1ZYMzFDYnAzY0ZPVmJqN2psbEZMQk9ObklLd3dma0RSN2Z2TDl6ZmZWZ3ZKdDNvVDk1XC85bTY3RTVuUHpoOW16TzJIcUtITGsxV05IUmF1cnJmUFQ1dUd1VyIsIm1hYyI6ImEyZjNhZGE2YTBlZDljZjhhMTAwYjVjNzVkYTU2YTg1NjlmODFmMzA2ZGU2OTFmOWE4MjNjYzQwM2NiNzAyYjIifQ=="

Can't think what else you'll need to know to help me. uh... help! (please)

0 likes
5 replies
Tippin's avatar

@meredevelopment I assume you also put their trait HasApiTokens on your user model? Only thing missing I may have noticed is axios headers. When a page loads up for you, do you properly get the csrf token and set it in the axios headers?

let token = document.head.querySelector('meta[name="csrf-token"]');
window.Laravel = { csrfToken: token.content };
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
1 like
meredevelopment's avatar

@tippin thanks for the ideas. Yes I have HasApiTokens in the model. I also have this in my bootstrap:

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

It didn't have window.Laravel = { csrfToken: token.content }; so I added that also but no luck/change.

In the loaded page I see: <meta name="csrf-token" content="gVFUHyeejt4bpEAvSrchXpP78aeRXQwHhvKBuxPv">

Does that all look ok?

Tippin's avatar

@meredevelopment Looks correct to me. Also, that window.Laravel was probably something from older bootstrap versions, but hey I keep in my js file. The only other thing I can think of may be a CORS issue. Not sure if your local frontend is hitting a different endpoint for backend.

One thing I forgot to ask though, how do you login on your web side? For the passport transient token to work, you must first auth your user from web, so regular auth middleware. Also be sure CreateFreshApiToken::class is at the bottom of the web middleware group. You may need a full page reload as well after web login for cookie to update.

1 like
meredevelopment's avatar
Level 3

Thanks for sticking with this one @Tippin. In the end I went back to a package by package check, and tried a few different Passport versions. Switching up to Passport 9 sorted things out. I see no difference 'mechanically' as to how the tokens were handled between 8.5 and 9, but... shrug

For any new types, or others like me that find package dependencies a dark-art, here's the composer.json line: "laravel/passport": "^9.0", or composer require laravel/passport "^9.0" from CLI.

skeith22's avatar

Good to see this is solve, just an addition for checking things out, you might want to check your <head> tag if it has the CSRF meta

<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">

This is usually the culprit, since axios usually does get this automatically though, it might have been this.

Anyway, kudos.

Please or to participate in this conversation.