Our application is comprised of an Ember.js SPA and a Rails API. We’re using lock.js.
Here’s the flow we have an issue with:
- Browser A is logged in
- Browser B is logged in
Now imagine a user logged into Browser A and B discovers she has been compromised. So the first thing she does is reset her password.
- Browser A requests a password change, receives the password change email, clicks the reset link and resets the password.
- Browser A remains logged in after the password change.
- Browser B appears to log the user out, but can simply click “log in” again, and click on their account listed under “last time you signed in with” and they are logged in again, without needing to know the updated password!
Step 5 is where everything goes wrong. Browser B should be forced to enter the new credentials to login again, but instead seemingly can just continue with the convenient last account used button.
You can just disable
rememberLastLogin on Lock.js (GitHub - auth0/lock: Auth0's signin solution) to avoid providing the last login button… but step 5 suggests that the frontend is still able issue new sessions with old credentials.
Ultimately this all boils down to: is it possible invalidate all other sessions and credentials when their password is reset? Forcing them to fully re-authenticate.
Others here are much better qualified to answer this than I am but I believe the short answer is “no”. Once a token is issued it is valid until it expires. You can set short expiry times like we do, but there is still a window where this sort of thing (there are other scenarios where this pops up) will happen.
I suspect you could get around it by having your app ping Auth0 for some indication of a change on the profile. E.g. check
updated_at but even then you need to decide how often to check the user profile.
I’ve got the same issue reported on a pentest. It’s not about JWT expiration time. I’ve reproduced the same behavior even with a one minute JWT exp.
The session managed by auth0, is not being closed after the user is updated.
This update can be a password change but also a mobile phone change for MFA, etc.
I also tried creating a rule to fix the issue, for example, storing the context.sessionId and the user.updated_at values. However, the sessionId is only maintain when using silent authentication (prompt=none), so there’s actually no way to securely achieve this.
Another option is to move this burden to each client application. The app will need to check for the updated_at value, compare it to the time in which its own session started, invalidate the client session and call the logout endpoint on the auth0 tenant.
Did anyone manage to solve this properly? Shouldn’t it be considered as a bug?
Update: there is no way to manage it client side. We needed to remove the session management from auth0, we simply can’t use the SSO feature. What’s the rationale for not invalidating the user session or at least have the option to do it in a rule?
Sorry for such huge delay in response! We’re doing our best in providing you with best developer support experience out there, but sometimes our bandwidth is not enough comparing to the number of incoming questions.
Wanted to reach out to know if you still require further assistance?
Any recommendations how do we implement having all sessions logout when the password is changed? In case a user remains logged in on another computer and someone else gains unauthorized access.
found there’s a last_password_reset in /users response. it is missing in the v3 api doc
how do we get this to appear in userinfo without using management api?
I have almost the same case, I just wanna keep one session opened.
After successfully validating an authentication request, any existing sessions associated with that credential should be invalidated and destroyed.
How can I invalidate or destroy the others sessions opened?
@vintg in a rule you can add the last_password_reset to the ID token, which will put it in the token and make it available via /userinfo. However it won’t update until the next time you get a new token.
context.idToken['https://mydomain.com/lastreset'] = user.last_password_reset;
Thanks a lot for sharing that knowledge Carlos!
This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.