Framework: Authorize middleware only works for default guard

Created on 31 May 2016  路  8Comments  路  Source: laravel/framework

On Laravel 5.2.32:

Route::group(['middleware' => ['auth:api']], function() {
    Route::group(['middleware' => 'can:view-internal'], function() {
    });
});

All routes within these groups will never be able to run if the default auth guard does not return a user, no matter the conditions for 'can:view-internal'.

AuthManager registers a userResolver callback which would accept a guard param but Gate::raw() is not supplying a guard. Probably because it does not know which one to use?

Possible solutions

  • Check all available guards in default userResolver for users, though that probably may be unexpected and result in security problems?
  • Specify which guard to use as param in middleware definition
  • Another config option to specify which guards to check for users
  • At least document that behaviour

Current fix for my case in register() of AuthServiceProvider, simply check both guards I care for:

Auth::resolveUsersUsing(function($guard = null) {
        return Auth::user() ? Auth::user() : Auth::guard('api')->user();
});

Most helpful comment

Did you try Auth::shouldUse('guard-that-you-want'); before calling Gate methods such as allows, denies, etc.?

I wouldn't overwrite the default guard for this.

All 8 comments

+1 - same problem occurs when using @can in Blade and I also traced it to Gate::raw() before I found this post. I am using separate guards for normal users and admins and cannot define admin policies.

@dan-iway's fix worked for me, but it is a workaround and could cause problems if user and admin rights overlap.

Not sure what the best fix for this would be...

Another temporary fix is to set the default guard on the fly in App\Http\Middleware\Authenticate:

class Authenticate
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        // Auth Logic

        // Change guard on runtime
        config(['auth.defaults.guard' => $guard]);

        return $next($request);
    }
}

The same is happening to me. I can login with two different guards, but when trying to get the user through Auth::user (), only the default guard works.

Same problem occurs using Policies, unable to make it use Auth::guard('api')->user()

edit: found a closed issue about it #14015

Here is a config option to change the default guard to api, In config/auth.php do:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'api',
        'passwords' => 'users'
    ],

Edit: To support a website and api see below for changing to use the 'api' guard on only API routes.

Did you try Auth::shouldUse('guard-that-you-want'); before calling Gate methods such as allows, denies, etc.?

I wouldn't overwrite the default guard for this.

Thanks @MladenJanjetovic calling Auth::shouldUse('api'); in the API controller constructor works, although it could also go in a custom middleware that only runs on api routes as long it is before any other middleware that uses Auth.

@malhal Yes, of course it could, and probably should, be in middleware. Please close this issue if it is resolved. Thanks

Was this page helpful?
0 / 5 - 0 ratings

Related issues

klimentLambevski picture klimentLambevski  路  3Comments

shopblocks picture shopblocks  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments

ghost picture ghost  路  3Comments

digirew picture digirew  路  3Comments