12

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?

3 Answers 3

23

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  \Illuminate\Http\Request $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 \App\Http\Kernel class.

protected $routeMiddleware = [
    'ajax' => \App\Http\Middleware\RequestIsAjax::class,
Sign up to request clarification or add additional context in comments.

10 Comments

Even changing that, if I put in my api.php Route::middleware('auth:api')->get('/latest', 'InternalApiController@latest'); I'm still getting the same error
@K3nzie you're still using auth:api which check for the api auth guard. Just use middleware('auth') and it will work.
ok fixed it, but still,this way the api endpoint is accessible from the web while only want it to be used from Vue, is that possible?
@K3nzie I added a simple AJAX check middleware which would help hide the API endpoints from an accidental browser navigation.
Works like charm! You saved me
|
3

With Laravel 8, I was getting a 401 error when trying to request something from the backend api. Following the accepted answer got me close, but it still didn't work. I believe this was because I have the dashboard on a subdomain as users.mydomain.tld and where I was using Axios was on the primary domain as mydomain.tld/some/path. The issue is the path for the session cookies. When re-configuring this, you need to clear all the cookies (dev toolbar). Then re-login like normal after you have made your changes. Else, the cookies will be messed up and you won't see it fixed or you wont be able to login at all until you clear them.

I reverted all the changes I made (following the accepted answer) and pinned down the SESSION_DOMAIN environment variable being the key ingredient, at least when it comes to the main user's area being on a sub-domain.

In your .env file:

SESSION_DOMAIN=".yourdomain.tld"

In app/Providers/RouteServiceProvider.php change api to web in the boot() method:

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

In routes/api.php:

Route::middleware('auth')->get('/user', function (Request $request) {
    return $request->user();
});

In your resources/js/bootstrap.js:

window.axios.defaults.withCredentials = true;

After modifying the bootstrap.js file, you will need to run npm run dev again to recompile.


Now, you should be able to use Axios in your frontend JavaScript. Whether it be jQuery or Vue, whatever you are using.

axios.get('/api/user')
    .then(response => console.dir(response.data))
    .catch(error => console.log(error));

1 Comment

I'm more suprised my question from 3 years ago still gets attention haha but good to know! useful information
0

CSRF-token is not the same as an authorization token. Most likely you will manually need to add the authorization token, which is probably like this, depending on your method of authorization.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.