Conversation
4ndrelim
left a comment
There was a problem hiding this comment.
Was investigating the bug too but saw you raised a PR before i did anything. So left some comments based on my udnerstanding. Seems like the right approach! Ill try to simulate some possible set-ups and test with ur fix.
| } | ||
|
|
||
| setTokens(token: string, refreshToken: string): void { | ||
| useAuthStore.getState().setToken(token); |
There was a problem hiding this comment.
May i check if im understanding the situation right. This fix is for 401 error?
In particular, when we refresh due to 401 error from sending a request with expired tokens, we get the new generated tokens but this was never updated to auth-store (browser localStorage). And so, on the next session, e.g. page reload, auth-store loads stale tokens leading to 401 token expiry error?
| token: resp.token, | ||
| refreshToken: resp.refreshToken, | ||
| }); | ||
| if (this.refreshPromise) { |
There was a problem hiding this comment.
nice dedup logic. Yes this should address the multiple async calls to refresh, leading to multiple redundant token generation, and possible 401 bug across sessions.
This is actually rather tricky to test though since i think the bug is probabilistic? i believe for the current session, neither caller (your e.g. v2/chats/models and v2/chats/conversations) will bug out since auth-store uses last write valid token. It is only when caller_A and caller_B each calls refresh() and backend mongo receives a different set of token from auth-store.
1. Local Storage Not Updated
Access tokens and refresh tokens are only saved to local storage on login, subsequent token refreshes do not update local storage.
Example: User refreshes to a new token and exits Overleaf, the next time he re-opens PaperDebugger, it uses the old refresh token.
Proposed solution: Update authStore whenever tokens are set.
2. Race Conditions When Refreshing
PaperDebugger often calls multiple endpoints at the same time, which results in a race condition if the token needs to be refreshed.
Example:
v2/chats/modelsandv2/chats/conversationsare called at the same time, and the access token needs refreshing, the refresh endpoint is called twice. In some occasions, the frontend uses the 2nd refresh token received which differs from the one stored in the backend. This can be easily reproduced by setting the JWT expiration in the backend to a very short time.Proposed solution: Use a promise for
refresh().Unsure if this fixes the exact problem in #110