0
votes

I've developed multiple traditional Laravel 5.x web apps with blade & Vue components, but now I'm developing a new Laravel 7 SPA app with React and Sanctum and I have installed the UI/Auth package (which is now separate).

I can log in with my React/Axios form, but can't get the logged in user (with "Auth::user()") in routes defined in "routes/api.php". But when I define a different route in "routes/web.php" that calls the exact same controller/method, I DO get the logged in user.

Maybe it has something to do with middleware definitions in "app/Http/Kernel.php" - I have:

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            EnsureFrontendRequestsAreStateful::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

Any thoughts?

2

2 Answers

0
votes

Its been a while since the post was made, and i am not aware if you have figured out the answer.

You might have forgotten to use the auth:sanctum middleware to be able to inject the current authenticated user.

Thats the only thing i can point to with what you have provided in terms of code.

-1
votes

The default api middleware stack is stateless. I don't know what your EnsureFrontendRequestsAreStateful::class does here.

So there are a couple solutions to fix this:

Add the same middleware as web

Add some extra middleware to your 'api' group so your cookies will identify your session (only the first one is mandatory), just as it works with the 'web' middleware:

StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,

Note that this makes your API stateful (since it now receives a session), which might be undesirable.

Use the built-in token guard for authentication

This is defined as the default driver for the api auth guard (see config/auth.php)

(https://github.com/laravel/laravel/blob/master/config/auth.php#L45)

It checks for the existence of (in this order):

  • An ?api_token=xxx query parameter
  • An api_token request body parameter
  • An Authorization: Bearer xxx header
  • A header named PHP_AUTH_PW

See https://github.com/laravel/framework/blob/7.x/src/Illuminate/Auth/TokenGuard.php#L97 Illuminate\Auth\TokenGuard::97 to see how this happens.

The token guard relies on an api_token column in your users table, which is checked against one of the items in the list above. See https://laravel.com/docs/6.x/api-authentication#database-preparation for an example migration on how to add this column.

Create a custom Auth guard in a service provider boot() method

As described here https://laravel.com/docs/7.x/authentication#closure-request-guards . For example, this one authenticates a user using an X-Api-Key header:

Auth::viaRequest('custom-token', function ($request) {
    return User::where('token', $request->header('X-Api-Key')->first();
});

You can then assign the 'driver' => 'custom-token' in your config/auth.php file.


Note that this all is dependent on the Illuminate\Auth\AuthServiceProvider::class, which should always be defined in your config/app.php['providers'] list. This is the basic service provider that makes sure that the Auth::user() functions etc. are available in your code.

So if you want to require authentication for particular routes, you'd have to add the 'auth' middleware (which is a shorthand for \App\Http\Middleware\Authenticate::class as seen in app\Http\Kernel::$routeMiddleware) to either your 'api' middleware group for api-wide authentication, or to separate routes.