Skip to content
Advertisement

API requests with axios always unauthorized with Laravel API

I’m working on a personal project using Laravel 5.6 and Axios library (standard Laravel 5.6 package).

I need to send first GET then POST request using Laravel’s API and axios’ http requests, but I’m not using Passport or any library like that since it’s an internal API serving only VueJS to obtain stuff from the database.

If I set my API routes using auth:api middleware, I always get unauthorized response, whichever is the request type, this is the error output :

Error: Request failed with status code 401

The message :

message: "Unauthenticated."

But, as I read in the documentation, axios headers are set inside laravel’s bootstrap.js to read the authorization token from meta tags (and the code is there) :

window.axios = require('axios');

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

// further down the file...
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');
}

While, if needed, here’s the http request code :

axios.post('/api/latest', formData)

So, why am I unauthenticated if those are set?

I’ve tried removing the auth:api middleware and, of course, it’s working:

- Route::middleware('auth:api')->get('/latest', 'InternalApiController@latestEp');
+ Route::get('/latest', 'InternalApiController@latestEp');

What am I doing wrong?

Advertisement

Answer

I’m not using Passort or any library like that since it’s an internal API serving only VueJS to obtain stuff from the database.

If the API is not stateless, meaning that the user is known to be logged in with a standard session cookie, then you can just use the default 'web' middleware for the API routes.

In the default RouteServiceProvider, change the mapApiRoutes function to use the web middleware instead:

protected function mapApiRoutes()
{
    Route::prefix('api')
        // ->middleware('api')
        ->middleware('web')
        ->namespace($this->namespace)
        ->group(base_path('routes/api.php'));
}

That being said, you should really put the API routes behind the default 'auth' middleware since they’re not throttled by default.

In the routes/api.php file:

Route::group(['middleware' => 'auth'], function() {
    Route::get('/latest', 'InternalApiController@latest');
});

And if you want to ensure it’s an AJAX request, you can create a simple middleware that checks that the request has the X-Requested-With header set to XMLHttpRequest.

class RequestIsAjax
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest $request
     * @param  Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!$request->ajax()) {
            return redirect()->route('login.index');
        }

        return $next($request);
    }
}

And register it within the $routeMiddleware array inside the AppHttpKernel class.

protected $routeMiddleware = [
    'ajax' => AppHttpMiddlewareRequestIsAjax::class,
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement