-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Token invalidation after canceled request by the frontend app #1232
Comments
@LeoValverde Maybe you can try increasing |
Thank you for the response, @MaicolBen! After the moment the frontend didn't recieve the most recent token, it's a matter of time for it to get disconnected, since the devise token auth doesn't repeat the most recent token. Increasing the |
@LeoValverde Thank you for identifying this problem and writing it up here. I was going nuts trying to figure out why I keep getting unauthorized responses. There are various scenarios that cause this and it seems to have been around since Oct 2014. I have added 100 bounty to the question. |
I found another SO question here which talks about a totally different solution, where refresh tokens are stored and they are used to issue the actual jwt access token (which is not stored). This is also the solution used by Auth0, explained here. This would require a fairly significant modification of this gem and would possibly be a breaking change...? |
@rmcsharry I've decided to adopt a simple solution that seems to be working very well. I'm not sure if it is the best way to workaround this issue, but it is the best I've got so far. After understanding how the devise token auth code, I've decided to override a small part of its behavior to get rid of the problem. BackgroundDevise token auth works with two tokens per user/client: the main one, called "token" which is the most fresh and the one that causes token rotation when sent back to the server; and the "last_one", which is valid for a few seconds (5 by default). Token rotation only happens when the token sent is the most fresh one. The token rotation works like that: The intention is to consider that there is one valid token that must be used to keep the normal token lifecycle going, but, in order to prevent network latency (and packages getting to the server in a different order), the last_token is a tolerance added to keep the last valid token as valid for a few more seconds. The concept of the solutionI assumed that it is super unlikely that the user will to cancel (by refreshing or closing the browser) a pending request that would come back with a new token 2 times in a row. The idea is to create an intermediary token, which I called "previous_token", that works exactly like the main one (the so called "token"). This means that it should rotate when it's recieved by the server and it should have the same validity of the main token. After the change, token rotation should work like that: This change would keep two tokens as valid (instead of one), and another one as a small tolerance, exactly as it were before. The codeTo implement this change, I just had to override two methods of the If the solution proves that it is stable and that it solves the problem, I think I'll try to reach the author of the library to explain the problem e propose the solution.
The change may seem big, but it is actually a copy paste of the two methods with a few small changes. I hope it works for you. Please, share your opinion about this alternative here. PS: I've seen in one of the links you shared that making two tokens valid at the same time would be a security issue. I'm not sure why is that. |
any action on this? |
I would like to hear from @lynndylanhurley. Maybe there is a better solution to this or perhaps I should make a pull request with this alternative I presented... |
@LeoValverde Thanks for that detailed explanation and solution. It makes total sense. I'm afraid it will be a couple of week before I can implement and test this. Having 2 tokens valid simultaneously is a security issue in case of hijacking - a hijacker could use to generate a new actual token (eg. that would then be valid for 2 weeks, or however long your validity period is for the JWT). However, in practice, I would argue that
I would love to hear from @lynndylanhurley on your proposed solution also. |
Has there been any movement on this at all? |
@LeoValverde sorry for the late response to this. Interesting idea - did your solution completely eliminate the problem? Seems like the security impact of this fix is marginal. The main security benefit of cycling the tokens is that the user will know quickly if their session has been hijacked, because their current session will be invalidated. I don't think we lose that with this fix. |
@lynndylanhurley my fix reduced A LOT the number of unauthorized responses, and made me able to keep using DTA in production. Even though, a few users still reporting sudden disconnections, and I think they are IPhone users. I really don't know why this happens to these people, but this problem moved from the top 1 bug and most important problem to solve, to something that annoys a really small portion of my users. In my humble opinion, this fix should be integrated to DTA, at least while we don't come up with a better and definitive solution. |
@LeoValverde - thanks for that feedback. Can you send a PR? If so I'll test and review ASAP |
@lynndylanhurley I'll do it ASAP! |
@lynndylanhurley I did it Thank you for addressing the problem. |
Fwiw my method for testing this was creating a super simple page that requests from our API on an interval that is slightly higher than the If I run this in multiple tabs (I usually do about 3), inevitably I hit a 401 on one tab, and all subsequent requests continue to work on all tabs. Keeping the network pane on chrome open is helpful in seeing the trail of requests. I can't be 100% sure it's the same issue as others are having and because it seems to be timing related, I can't reliability reproduce it. It certainly seems like having 2+ validatable tokens would fix this, but it seems hard to know since I can't find a way to reproduce on demand. |
@LeoValverde @MaicolBen |
Added a PR for this. Review requested @MaicolBen @lynndylanhurley |
I'm using devise token auth and implementing my own logic at the front-end to handle the token management.
After many of my users reporting a sudden token invalidation, I found out that this is caused when the frontend makes the request and cancels it (it happens when we refresh the browser in the middle of the promise runtime).
When the backend generates a new token but the frontend app is no longer listening to the response, the frontend only has the "last token" to work with instead of the newest one. After five seconds, the old token expires and the user is kicked out to the login page.
Any ideas to solve this?
Considering I could implement any logic in the frontend to put the authentication back on track after this event, I would still need more functionality in the devise token auth lib?
The text was updated successfully, but these errors were encountered: