-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[10.x] Use AuthenticateSession on Sanctum requests #48056
[10.x] Use AuthenticateSession on Sanctum requests #48056
Conversation
* password hash should be stored and used across all guards, not individually; as the same user is authenticated in each * default guard's viaRemember to false * implement logoutCurrentDevice for all guards.
Surely this removes existing functionality where the passwords were maintained separately for each guard? |
Maintaining passwords for each guard is one of the reasons the current If it were always the framework/src/Illuminate/Auth/AuthManager.php Lines 191 to 225 in c1e6281
This creates a mismatch when updating the password, as the new password hash is only stored for the guard that changed it, the others are logged out (in the same session) |
But I guess what I'm saying is surely we added that for a reason and just removing it would break applications that rely on it? Maybe there is a better way to solve this? |
I think it's because you can have multiple user tables, some separate them as admins, users and this would break it as changing user or admin password would invalidate others. BUT, I know there also are situations where you separate the sessions but use the same users table (with rare additions such as user_profiles table etc.) and same password where existing logic makes less sense as the password is shared and should invalidate both sessions. Maybe instead of a driver name it should target user provider name, but this definitely should not go into 10.x.. That's my theoretical guess. |
Can you make the test repository available for further debug and tests: https://github.com/patrickomeara/sanctum-logout-issue |
@crynobone Sorry I thought that was public already. @taylorotwell I had the same thought when I first started working on this. I initially tried to iterate over all of the guards and update the password hash, which is essentially not storing it per guard (but does give some BC, as mentioned in my first comment). The original PR doesn't give much info away. The storing of the hashed password is only for stateful requests in the same session. The problem is changing the password only updates the guard that changed it. But the desired outcome is to keep all guards in the session logged in, and log out other sessions. I've targeted 10.x only for security reasons. This can be changed. |
After looking at the structure I do think the solution isn't the best:
I believe |
@crynobone Thanks for looking into this! The first approach I took introduced a sanctum only middleware. https://github.com/laravel/sanctum/pull/461/files Let me know if I can help further. |
@patrickomeara yeah - I agree your original pull request was more on the right track. |
Closing this because at minimum we need to go back to the other PR. This one is breaking. |
I'll circle back on this when I get a chance. |
@patrickomeara Can you check and verify laravel/sanctum#467 |
This PR allows
auth.session
to be used afterauth:sanctum
to logout other session on password change.It is a better approach to my existing sanctum PR where I attempted to solve the issue by introducing a stripped-down version of
AuthenticateSession
. This PR has a better DX as it keeps theauth.session
implementation that developers already know.The
AuthenticateSession
middleware makes it possible to invalidate sessions on other devices https://laravel.com/docs/10.x/authentication#invalidating-sessions-on-other-devicesThe problem
If a user is logged in in two different browsers, and change their password in one, the web guard is invalidated in the other, but the sanctum guard is not and requests can still be sent to the API.
If a bad actor had access to a web session, they still have access to the sanctum guarded API after a password update.
Currently, using
auth.session
on Sanctum frontend requests will throw two fatal errors asRequestGuard
doesn't haveviaRemember
orlogoutCurrentDevice
methods. These have been added to theGuardHelpers
trait with sensible defaults for both framework and custom guards.Password Hash
This PR also reverts a change where the password hash was stored per guard. #33876
I can't see an advantage of storing the password hash per guard as the same user is authenticated across guards even in multi guard auth. If a request changes the user's password the password hash should update for all guards in the session, not just the guard that changed it. Additionally, the author of that PR has been deleted from github. I'd be grateful if anyone can shed some light on this change and the issue it was addressing.
Test Repo
As this is a difficult scenario to test I have created a test repo.
The main branch of the test repo shows the issue, where the user can still make a sanctum request after a password change in another session. The web guard has been logged out here, but not the sanctum guard.
Screen.Recording.2023-08-14.at.11.45.12.mov
The auth.session branch of the test repo uses this PR branch of
laravel/framework
to show the request now returns a 401 and has logged the user out of both web and sanctum guards.Screen.Recording.2023-08-14.at.11.58.19.mov
The difference between the branches can be viewed here.
Dusk/Jetstream
If this PR is accepted Dusk and Jetstream will need a small change to the logout mechanisms to remove the guard suffix.
https://github.com/laravel/dusk/blob/1040b15b78ed829ba1166ef10757385b0416ae8e/src/Http/Controllers/UserController.php#L63
https://github.com/search?q=org%3Alaravel+password_hash_+repo%3Alaravel%2Fjetstream&type=code
Backward Compatibility
This is a breaking change if developers are interacting with
password_hash_<guard>
in the application layer. In this case, we could iterate over the guards and setpassword_hash_<guard>
for each one, and leave thepassword_hash
change to 11.x. The downfall with this approach is: unless we can collect all of the guards the app uses, not just the request, we end up in the same situation.The
AuthenticateSession
middleware addspassword_hash
if it is not currently present before the request proceeds. if the application layer does not interact withpassword_hash_<guard>
this change will not break existing functionality.Any existing sanctum guarded sessions will still be valid after the
auth.session
middleware is added as the first request will set it. However, all subsequent requests after a password change will be logged out. This will still be an issue if this change were to target 11.x.It should be noted that Laravel 7.x used the key
password_hash
if a session is still in use from 7.x updating to this will log sessions out that have had a password change since the 7.x request was made. Changing the key to something new will alleviate this edge case iehashed_password