If I understand correctly, the user id is stored in the session or cookie (when remembered), so there is no way to log a user out of existing sessions, right?
So if somebody guesses someones password or forgets to log out from a computer, there is no way to destroy these sessions, right?
It would be nice to be able to do so, for example a button to logout all users or whenever you change your password, reset existing sessions.
I see that this probably isn't really easy in the way it currently is, but perhaps en extra 'token' field with a random string, that is also stored in the session/cookie, as en extra check besides the user id?
I would suggest returning false from attempt if auth.attempt event explicitly returns false.
This would be a more general solution as you could hook into the attempt event and fail it on your own conditions.
ps.: If you need to add your own session data on auth just listen to auth.login.
I'm not sure if I understand you. Right now, when the login is remembered, it is not attempted, right? It just checks if the user id exists and if so, logged in as that user. And there is no event for logging in automatically, right?
You're right, it was my confusion -- need to sleep.
But you are right, an event before the user is loggedin from a cookie, would be useful, so we can anyone can do extra checks if they want and return false to disable auto-login.
The Auth::logout function deletes the remember me cookie as well as the "regular" cookie. Is that what you want?
No. I mean that if I am on my PC, I want to be able to logout my laptop/phone/tablet and every other device.
Or at least provide an event to do that check. When attempting to login, you can provide extra checks (active=true in the example), but when active=true, it isn't checked anymore, right? It's just logged in.
And for login, there is an even, so I suppose you can block that with extra security checks. But when a user is remembered, that is not possible.
So what about an event (auth.remembered), that passed the user object of remembered user. You can then check if active still is true or for example, if I want to log everyone out, I change some random token which doesn't match anymore and return false to block the attempt.
(Offcourse only for cookies, not for the session everytime)
I agree this would be good for security. I'm not sure if it could/should be in core Laravel, but additional events to hook into would be good.
I'm currently using a custom user provider that checks if the password has been changed since they logged in by storing a timestamp with the ID. That way if the user changes the password on any device they are logged out of all others.
class User extends Eloquent implements UserInterface {
public function getAuthIdentifier()
{
return $this->id . ':' . $this->password_changed;
}
}
class MyUserProvider implements UserProviderInterface {
public function retrieveByID($token)
{
// Login from session/cookie
@list($id, $password_changed) = explode(':', $token);
if (!$id) return;
// Fetch the user
$user = User::find($id);
// If the password has been changed, log out all existing sessions
if ($user and $user->password_changed !== $password_changed) return;
return $user;
}
}
Everyone doing their own way, I use a timed token which stores a datetime and a random string, and the user from the user security page can delete the token of other machines at this way u can logoff your phone from your computer.
This proposal made me thinking, I personaly should remove the whole auth from a framework but Laravel pretty awesome with it and extends the programers life span as well, but for the truth more and more end user uses multiple device at the same time (pc+phone+tablet) and this feature looks like a useful addition.
Yeah, I think it doesn't really have to be in the framework by default, but maybe auth.remember (when saving the cookie) and auth.remembered (for when remembering a user), with ability to block logging in with a cookie, would make it much easier to implement.
OK, I understand the use case now, but we really don't have anyway to connect multiple sessions across the same user. I wouldn't have a good way to identify them without quite a bit more code on our end I think. If anyone has a relatively simple solution I'm all ears though.
So what about extra events to let developers do the extra checking?
Which events would you need? You mentioned remembering... we do have the viaRemember method now you might be able to check on login
event.
I'm not really sure, maybe I'm overlooking something.
When logging in through Auth::attempt(), an auth.login is fired after logging in, with the $remember value. So I can add some extra data to the cookies, that seems okay.
But how do I know when the user is logged in through a cookie?
Here, the user for Guard is set: https://github.com/laravel/framework/blob/master/src/Illuminate/Auth/Guard.php#L140
But no attempts are fired, right?
This could be fixed by using loginUsingId($recaller), then the auth.login is also fired on cookie logins.
And to know if it is remembered, viaRemember would have to be set before the event is fired, not after.
And a few things I noticed in Guard.php:
In my opinion this could all relatively easily be fixed by linking the cookie data to "auth sessions" in the database. Store a session in the database for each device a user logs in from, link the cookie to that session, check that the session still exists in the database and didn't expire when a user is auth checked through the cookie, and when you want to log one particular session out, just delete that entry from the database.
Since it seems this issue hasn't been addressed in the last few months, I'll have a go at it and see what I come up with.
This is fixed now by https://github.com/laravel/framework/commit/c5ac19e1eb809c486b04e0f6867aeaf0e81e7afd :)
Finally reached here after dug through half the internet. My question is same as @barryvdh has. How to log out programmatically user's all sessions across all logged in devices? Or for example list all user sessions and then programmatically delete specific session. It would be very neat to list in the web app all user active sessions, and for user to be able to destroy them.
Also last commit I don't completely understand how to retrieve user session? Passing Session::getId() will only get current browsers session, but what about other browsers? Also I'm using Redis as a driver for sessions.
Thank alot, hopefully someone will see that and point correct solution.
I have the same task. Has anybody solved this problem?
Event::listen('auth.login', function($user)
{
$session = Session::getId();
AuthService::saveBrowserSession($user, $session); // save to db that session
}
And $session just save into DB, and then you can delete it programmatically
$userSession->delete();
// if session is current browser session, flush it !!!!
if ($session == Session::getId())
{
Session::flush();
}
In my application admin can enable or disable user account. How can i end the session of disabled users???
@jkunwar Currently you would need to add a middleware that checks if the logged in user is still active on every request. There is no way to invalidate a previously issued session token cookie that is not a remember_me cookie AFAIK.
Thank you for your suggestion.
But in my case i created a session table and when admin disables a user i
flushed out his session data from the table and it is working fine.
On Fri, Aug 18, 2017 at 6:07 AM, Daniel Speichert notifications@github.com
wrote:
@jkunwar https://github.com/jkunwar Currently you would need to add a
middleware that checks if the logged in user is still active on every
request. There is no way to invalidate a previously issued session token
cookie that is not a remember_me cookie AFAIK.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/laravel/framework/issues/2444#issuecomment-323227876,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AdbW1QEpJytWXtYAzRBA_U4sH0QGg-4cks5sZNldgaJpZM4BFEWx
.
@skyzer thanks for your code, I was wrapping my head around how to do this but your code makes it very simple to just add to a middleware to invalidate a session.
It would be nice if Laravel provided a way to get session information by user ID, something like Session::findByUserId($id);
that returns an array of session data such as id, etc. That way it would work independent of the session driver you use - for example we use Redis but then storing the session ids against users in the database as well seems a bit unnecessary given that Redis is probably already storing the data and can be queried in some way.
Along with this would be nice to be able to flush a single session id:
Session::flushId($sessionId);
But maybe that's already possible if your using the cache driver could you just do something like Cache::forget($sessionId)
?
With 5.6 logoutOtherDevices function I was able to come up with this solution. But as a side effect banned user's password will be changed to random. I suppose there is a way to avoid setting and resetting auth user.
Capture current user.
$admin = auth()->user();
Set user to banned, and logout.
Auth::setUser($user)->logoutOtherDevices(str_random());
Set back our admin.
Auth::setUser($admin);
Just thought I'd mention this as there was some interest in my original comment about listing and flushing/logging out of individual sessions - there's an interesting suggestion on stackoverflow where you can log individual sessions, list, and log them out as nesscary: https://stackoverflow.com/a/31937908/63523 - I can see this working by listening for authentication events, storing additional information in Redis/database about active sesions, ips, etc.
At the moment, Laravel only supports a logoutOtherDevices($newPassword)
method which has many drawbacks:
Hopefully the link above will provide some ideas on how to have a bit more flexibility and functionality.
Most helpful comment
@skyzer thanks for your code, I was wrapping my head around how to do this but your code makes it very simple to just add to a middleware to invalidate a session.
It would be nice if Laravel provided a way to get session information by user ID, something like
Session::findByUserId($id);
that returns an array of session data such as id, etc. That way it would work independent of the session driver you use - for example we use Redis but then storing the session ids against users in the database as well seems a bit unnecessary given that Redis is probably already storing the data and can be queried in some way.Along with this would be nice to be able to flush a single session id:
Session::flushId($sessionId);
But maybe that's already possible if your using the cache driver could you just do something like
Cache::forget($sessionId)
?