404labfr / laravel-impersonate

Laravel Impersonate is a plugin that allows you to authenticate as your users.
https://marceau.casals.fr
2k stars 202 forks source link

After Auth::user()->impersonate($otherUser) I'm getting logged out #154

Open core45 opened 2 years ago

core45 commented 2 years ago

I've installed the package as described and tried to impersonate other user. But I'm always getting logged out.

Here is my code:

$anotherUser = User::find(9); Auth::user()->impersonate($anotherUser); return redirect()->route('dashboard');

core45 commented 2 years ago

Ah. And I'm using Jetsream

relaypilot commented 2 years ago

I'm experiencing the same issue after updating composer:

It was working fine with Laravel 9.3.1, and breaks after upgrading to 9.4.x

Here is the Laravel changelog: https://github.com/laravel/framework/blob/9.x/CHANGELOG.md#v940---2022-03-08

relaypilot commented 2 years ago

Quick fix is to comment out the following line in Illuminate\Foundation\Http\Kernel.php:

    protected $middlewarePriority = [
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
        // Comment out this line:
        // \Illuminate\Contracts\Session\Middleware\AuthenticatesSessions::class,
        // Add this line:
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];
core45 commented 2 years ago

I do not have anything like \Illuminate\Contracts\Session\Middleware\AuthenticatesSessions::class, in Illuminate\Foundation\Http\Kernel.php

I tried to comment out this line instead: \Laravel\Jetstream\Http\Middleware\AuthenticateSession::class,

but it did not help. I'm still getting log out.

core45 commented 2 years ago

And I'd like to comment one important thing to the maintainer of this package. I can understand that the package can not work with some other software like JetStream. But for a f..k sake why didn't you warn us about it? I really appreciate your hard work and I know this package is free and comes with no guarantee whatsoever but I feel that respect should be mutual. I just lost many hours trying to make work something which is faulty. If the author was honest and put any information about the situation in the readme it would spare me hours of useless work.

relaypilot commented 2 years ago

This should now be fixed if you upgrade to Laravel Framework 9.5.1: https://github.com/laravel/framework/pull/41491

Update: after checking, it didn't resolve it for me, still experiencing the same issue.

luigel commented 2 years ago

@core45 I fixed this one by updating the middleware of the routes generated by jetstream

-Route::group(['middleware' => ['auth:sanctum', 'verified']], function (): void {
+Route::group(['middleware' => ['auth:web', 'verified']], function (): void {
//
});

Im using laravel nova to impersonate and nova is using a web auth guard. So the nova and jetstream was not using the same guard. Because by default the jetstream's guard is using sanctum.

This package when impersonating is logging in the user using the current guard which is web but redirects to the dashboard in jetstream which is a sanctum guard.

seabasss commented 2 years ago

So, either removing \Laravel\Jetstream\Http\Middleware\AuthenticateSession::class from App\Http\Kernel.php or changing sanctum to web in the routes file seems to fix this with Jetstream. Does anyone know the implications of doing any of those options?

Coding-Kiwi commented 2 years ago

@seabasss The main reason why auth:sanctum is in your routes/web.php can be read in the docs

You may be wondering why we suggest that you authenticate the routes within your application's routes/web.php file using the sanctum guard. Remember, Sanctum will first attempt to authenticate incoming requests using Laravel's typical session authentication cookie. If that cookie is not present then Sanctum will attempt to authenticate the request using a token in the request's Authorization header. In addition, authenticating all requests using Sanctum ensures that we may always call the tokenCan method on the currently authenticated user instance:

So basically if you do not need sanctum in your web routes, use auth:web Which is what I did and it fixed the issue.

But nevertheless it would be interesting to know why impersonation with auth:sanctum worked for me in laravel 8 and not in laravel 9

seabasss commented 2 years ago

Thanks for the info! It actually worked in 9 for me up until v9.4. And it works with sanctum for me after updating some files to reflec latest jetstream, however it doesn’t work if I add the new jetstream config parameter in the route middleware.

Mahegus commented 2 years ago

A simple solution to get the impersonating working for a Jetstream/Sanctum setup is to use the event TakeImpersonation and add the missing session key required for Sanctum authentification

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
    session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
});

still working on the LeaveImpersonation.

mkamranmalik72 commented 2 years ago

Facing the same issue any luck?

seabasss commented 2 years ago

A simple solution to get the impersonating working for a Jetstream/Sanctum setup is to use the event TakeImpersonation and add the missing session key required for Sanctum authentification

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
    session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
});

still working on the LeaveImpersonation.

Where do you put that? Thx

Mahegus commented 2 years ago

You put it in the boot method of your EventServiceProvider

Event::listen(function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
    session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
});
invaders-xx commented 2 years ago

I am using latest L9, without Jetstream, and impersonating gets me to login page. If I comment AuthenticateSession middleware, it works. Did anyone face this issue too ? How did you solve it ?

m7vm7v commented 2 years ago

A simple solution to get the impersonating working for a Jetstream/Sanctum setup is to use the event TakeImpersonation and add the missing session key required for Sanctum authentification

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
    session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
});

still working on the LeaveImpersonation.

All cool and beans mate, thanks a lot, I think this is the cleanest of the options.

Were you able to get the LeaveImpersonation working too?

Mahegus commented 2 years ago

A simple solution to get the impersonating working for a Jetstream/Sanctum setup is to use the event TakeImpersonation and add the missing session key required for Sanctum authentification

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
    session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
});

still working on the LeaveImpersonation.

All cool and beans mate, thanks a lot, I think this is the cleanest of the options.

Were you able to get the LeaveImpersonation working too?

Sadly not, Its not currently a problem, as when logging in as an admin user, i just redirect to the admin area instead.

illusive-ch commented 2 years ago

I was able to get leave working thanks to @matt127127 @m7vm7v looks like there is an impersonator object on the event, for anyone else just throw this in a listener or right on the web.php

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
    });
Event::listen(\Lab404\Impersonate\Events\LeaveImpersonation::class,
    function(\Lab404\Impersonate\Events\LeaveImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonator->getAuthPassword());
    });
Mahegus commented 2 years ago

I was able to get leave working thanks to @matt127127 @m7vm7v looks like there is an impersonator object on the event, for anyone else just throw this in a listener or right on the web.php

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
    });
Event::listen(\Lab404\Impersonate\Events\LeaveImpersonation::class,
    function(\Lab404\Impersonate\Events\LeaveImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonator->getAuthPassword());
    });

@illusive-ch I have tried using the LeaveImpersonation::class but to no avail, If you manage to get it working i would love to see how you did it.

illusive-ch commented 2 years ago

@matt127127 thats exactly what I put in my routes file to get it to stop from logging out when u leave impersonation.

Mahegus commented 2 years ago

@matt127127 thats exactly what I put in my routes file to get it to stop from logging out when u leave impersonation.

@illusive-ch What version of Laravel are you using, i'm using 9.17 and it just doesn't want to play ball for me.

illusive-ch commented 2 years ago

@matt127127

> art --version
Laravel Framework 9.13.0

When I set this up I setup my own routes as well let me get the code for you: web.php

Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
    });
Event::listen(\Lab404\Impersonate\Events\LeaveImpersonation::class,
    function(\Lab404\Impersonate\Events\LeaveImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonator->getAuthPassword());
    });
Route::middleware([
    'superadmin'])
    ->name('admin.')
     ->prefix('admin')
     ->group(function () {
         Route::resource('user', \App\Http\Controllers\Admin\UserController::class);
         Route::get('user/{user}/impersonate', '\App\Http\Controllers\Admin\UserController@impersonate')->name('user.impersonate');
         Route::get('user/{user}/leave-impersonate', '\App\Http\Controllers\Admin\UserController@leaveImpersonate')->name('user.leave-impersonate');
     });

Usercontroller.php

    public function impersonate(User $user)
    {
        auth()->user()->impersonate($user);

        return redirect()->route('dashboard');
    }
    public function leaveImpersonate()
    {
        auth()->user()->leaveImpersonation();

        return redirect()->route('dashboard');
    }

Let me know if that works for you

Mahegus commented 2 years ago

@illusive-ch Sadly that didn't work, it seemed to make it worse for me, i couldn't even impersonate.

dominik-eller commented 2 years ago

For me it is working with default setup of this module without any events on local valet setup but not on production server (forge). I am using spatie/laravel-permissons and sanctum with Jetstream

heychazza commented 2 years ago

Still facing this issue with Jetstream..

webtamizhan commented 2 years ago
Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
    });
Event::listen(\Lab404\Impersonate\Events\LeaveImpersonation::class,
    function(\Lab404\Impersonate\Events\LeaveImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonator->getAuthPassword());
    });
Route::impersonate();

Can you please try this?

dominik-eller commented 2 years ago
Event::listen(\Lab404\Impersonate\Events\TakeImpersonation::class,
    function(\Lab404\Impersonate\Events\TakeImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonated->getAuthPassword());
    });
Event::listen(\Lab404\Impersonate\Events\LeaveImpersonation::class,
    function(\Lab404\Impersonate\Events\LeaveImpersonation $event) {
        session()->put('password_hash_sanctum', $event->impersonator->getAuthPassword());
    });
Route::impersonate();

Can you please try this?

This does not seem to work. After a fresh deploy I could impersonate once. Leaving this impersonation did not work and further impersonation did not work as well. I am getting logged out.

On my local machine the default is working (without any need of manipulation). On the laravel forge server with deploying over envoyer it is not working - even with your manipulation.

mkamranmalik72 commented 2 years ago

I'm using Laravel 8 + Inertia Js for authentication using Fortify but impersonating not working logged out as well, kindly someone helps me out with this issue, maybe it is working on simple Laravel older versions but in with Inertia js + Fortify it is not working I tried all above solutions.

apydevs commented 1 year ago

With jetstream check the jetstream config file, as this also has 'guard' set to sanctum change this to 'web'

` /* -------------------------------------------------------------------------- Jetstream Guard
Here you may specify the authentication guard Jetstream will use while
authenticating users. This value should correspond with one of your
guards that is already present in your "auth" configuration file.
*/

'guard' => 'web',`
dominik-eller commented 1 year ago

With jetstream check the jetstream config file, as this also has 'guard' set to sanctum change this to 'web'

` / |-------------------------------------------------------------------------- | Jetstream Guard |-------------------------------------------------------------------------- | | Here you may specify the authentication guard Jetstream will use while | authenticating users. This value should correspond with one of your | guards that is already present in your "auth" configuration file. | /

'guard' => 'web',`

There is no "guard" section in my jetstream config file.

apydevs commented 1 year ago

With jetstream check the jetstream config file, as this also has 'guard' set to sanctum change this to 'web' ` / |-------------------------------------------------------------------------- | Jetstream Guard |-------------------------------------------------------------------------- | | Here you may specify the authentication guard Jetstream will use while | authenticating users. This value should correspond with one of your | guards that is already present in your "auth" configuration file. | /

'guard' => 'web',`

There is no "guard" section in my jetstream config file.

I'm currently on version 2.12.6 of Jetstream, what version are you currently running?

dominik-eller commented 1 year ago

2.9.0 but I checke the latest v.2 release and the master branch on GitHub and there is no guard section as well.

With jetstream check the jetstream config file, as this also has 'guard' set to sanctum change this to 'web' ` / |-------------------------------------------------------------------------- | Jetstream Guard |-------------------------------------------------------------------------- | | Here you may specify the authentication guard Jetstream will use while | authenticating users. This value should correspond with one of your | guards that is already present in your "auth" configuration file. | /

'guard' => 'web',`

There is no "guard" section in my jetstream config file.

I'm currently on version 2.12.6 of Jetstream, what version are you currently running?

2.9.0 but I checke the latest v.2 release and the master branch on GitHub and there is no guard section as well.

apydevs commented 1 year ago

2.9.0 but I checke the latest v.2 release and the master branch on GitHub and there is no guard section as well.

With jetstream check the jetstream config file, as this also has 'guard' set to sanctum change this to 'web' ` / |-------------------------------------------------------------------------- | Jetstream Guard |-------------------------------------------------------------------------- | | Here you may specify the authentication guard Jetstream will use while | authenticating users. This value should correspond with one of your | guards that is already present in your "auth" configuration file. | /

'guard' => 'web',`

There is no "guard" section in my jetstream config file.

I'm currently on version 2.12.6 of Jetstream, what version are you currently running?

2.9.0 but I checke the latest v.2 release and the master branch on GitHub and there is no guard section as well.

I believe the config is generated from this stub https://github.com/laravel/jetstream/blob/2.x/stubs/config/jetstream.php Line 47

As im sure you know using php artisan vendor:publish will give you a list and in there will be jetstream-config, when this is selected this way I'm sure it generates the jetstream config from the stub in the link.

If you have customised the config for jetstream try coping the 'guard' => 'sanctum', changing to web in your current config file.

Hope this helps

dominik-eller commented 1 year ago

2.9.0 but I checke the latest v.2 release and the master branch on GitHub and there is no guard section as well.

With jetstream check the jetstream config file, as this also has 'guard' set to sanctum change this to 'web' ` / |-------------------------------------------------------------------------- | Jetstream Guard |-------------------------------------------------------------------------- | | Here you may specify the authentication guard Jetstream will use while | authenticating users. This value should correspond with one of your | guards that is already present in your "auth" configuration file. | /

'guard' => 'web',`

There is no "guard" section in my jetstream config file.

I'm currently on version 2.12.6 of Jetstream, what version are you currently running?

2.9.0 but I checke the latest v.2 release and the master branch on GitHub and there is no guard section as well.

I believe the config is generated from this stub https://github.com/laravel/jetstream/blob/2.x/stubs/config/jetstream.php Line 47

As im sure you know using php artisan vendor:publish will give you a list and in there will be jetstream-config, when this is selected this way I'm sure it generates the jetstream config from the stub in the link.

If you have customised the config for jetstream try coping the 'guard' => 'sanctum', changing to web in your current config file.

Hope this helps

There is no guard directive. I just updated via composer and did a vendor publish...

Bildschirm­foto 2022-12-08 um 20 52 21
apydevs commented 1 year ago

@arumcomputer Only trying to assist .... Do a search of the repo there are many references to the jetstream config using config('jetstream.guard') https://github.com/laravel/jetstream/search?p=1&q=guard

What do you have in your LaravelProject/config/jetstream.php file?

dominik-eller commented 1 year ago

@

I am very very thankful for your assist. Waited so long... I guess it is just named "middleware" instead of "guard". Here is my jetstream config:

'stack' => 'livewire', 'middleware' => ['web'], 'features' => [ // Features::termsAndPrivacyPolicy(), // Features::profilePhotos(), // Features::api(), Features::teams(['invitations' => true]), //Features::accountDeletion(), ], 'profile_photo_disk' => 'public',

But I do find "jetstream.guard" in the vendor folder. Maybe I can just add that directive to my config file?

apydevs commented 1 year ago

@arumcomputer, No problem, let's see if we can get it sorted. You should be able just to add it in, I have both middleware and guard see my config below

'stack' => 'livewire',
'middleware' => ['web'],
'auth_session' => AuthenticateSession::class,
'guard' => 'web',
'features' => [
    // Features::termsAndPrivacyPolicy(),
    // Features::profilePhotos(),
    // Features::api(),
    Features::teams(['invitations' => true]),
    Features::accountDeletion(),
],
'profile_photo_disk' => 'public',
dominik-eller commented 1 year ago

ok, just added 'guard' => 'web' and it does not work for me. But what is that... 'auth_session' => AuthenticateSession::class ?

Which class do you use here? Laravel\Jetstream\Http\Middleware\AuthenticateSession; ?

apydevs commented 1 year ago

Yeah its use Laravel\Jetstream\Http\Middleware\AuthenticateSession;

dominik-eller commented 1 year ago

@apydevs does not fix it. I can't believe it's to hard.

apydevs commented 1 year ago

In your web route, files are you is auth: sanctum. anywhere. ?

dominik-eller commented 1 year ago

In your web route, files are you is auth: sanctum. anywhere. ?

Yes, I am using auth:sanctum in a route group.

apydevs commented 1 year ago

In your web route, files are you is auth: sanctum. anywhere. ?

Yes, I am using auth:sanctum in a route group.

Out of interest does change this to auth:web make a difference?

dominik-eller commented 1 year ago

In your web route, files are you is auth: sanctum. anywhere. ?

Yes, I am using auth:sanctum in a route group.

Out of interest does change this to auth:web make a difference?

with auth:web instead of auth:sanctum the impersonation works as expected. But I don't know if any other authentication does throw an unexpected exception now.

apydevs commented 1 year ago

In your web route, files are you is auth: sanctum. anywhere. ?

Yes, I am using auth:sanctum in a route group.

Out of interest does change this to auth:web make a difference?

with auth:web instead of auth:sanctum the impersonation works as expected. But I don't know if any other authentication does throw an unexpected exception now.

Well that's the first step getting it working as expected , i know sanctum is built more for SPA & mobile applications, and simple, token based APIs. From what i can tell your using the livewire stack, so shouldn't affect it. if you planning on using the user API feature within jetstream it may be worth going through and checking that & accessing from postman just to be sure.

dominik-eller commented 1 year ago

I am using auth:sanctum in api route and my app is working. I tested the frontend as well and it seems to work. I ask myself why I was using auth:sanctum in web route.

apydevs commented 1 year ago

I think you will find when you did the php artisan jetstream:install livewire --teams

it changes all the auth:web to auth:sanctum

https://github.com/laravel/jetstream/blob/bfed92ddacb22053ddfe1208f098fbd9d9404d89/src/Console/InstallCommand.php. Line 293

seabasss commented 1 year ago

I'm using this:

Route::middleware([
    'auth:web,sanctum',
    config('jetstream.auth_session'),
    'verified',
])
dominik-eller commented 1 year ago

I think you will find when you did the php artisan jetstream:install livewire --teams

it changes all the auth:web to auth:sanctum

https://github.com/laravel/jetstream/blob/bfed92ddacb22053ddfe1208f098fbd9d9404d89/src/Console/InstallCommand.php. Line 293

oh yes, I am using team feature. Does it need to be auth:sanctum for that or will it be fine with auth:web?

Do you have another solution to use impersonation with auth:sanctum?

apydevs commented 1 year ago

@arumcomputer Not with auth: sanctum as of yet, I'm using teams with Auth: web and it's been fine.