-
Notifications
You must be signed in to change notification settings - Fork 61
fix: tokens #113
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
base: main
Are you sure you want to change the base?
fix: tokens #113
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ import { EventEmitter } from "events"; | |
| import { ErrorCode, ErrorSchema } from "../pkg/gen/apiclient/shared/v1/shared_pb"; | ||
| import { errorToast } from "./toasts"; | ||
| import { storage } from "./storage"; | ||
| import { useAuthStore } from "../stores/auth-store"; | ||
|
|
||
| // Exhaustive type check helper - will cause compile error if a case is not handled | ||
| const assertNever = (x: never): never => { | ||
|
|
@@ -29,6 +30,7 @@ class ApiClient { | |
| private axiosInstance: AxiosInstance; | ||
| private refreshToken: string | null; | ||
| private onTokenRefreshedEventEmitter: EventEmitter; | ||
| private refreshPromise: Promise<void> | null = null; | ||
|
|
||
| constructor(baseURL: string, apiVersion: ApiVersion) { | ||
| this.axiosInstance = axios.create({ | ||
|
|
@@ -64,6 +66,8 @@ class ApiClient { | |
| } | ||
|
|
||
| setTokens(token: string, refreshToken: string): void { | ||
| useAuthStore.getState().setToken(token); | ||
| useAuthStore.getState().setRefreshToken(refreshToken); | ||
| this.refreshToken = refreshToken; | ||
| this.axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${token}`; | ||
| } | ||
|
|
@@ -89,15 +93,27 @@ class ApiClient { | |
| } | ||
|
|
||
| async refresh() { | ||
| const response = await this.axiosInstance.post<JsonValue>("/auth/refresh", { | ||
| refreshToken: this.refreshToken, | ||
| }); | ||
| const resp = fromJson(RefreshTokenResponseSchema, response.data); | ||
| this.setTokens(resp.token, resp.refreshToken); | ||
| this.onTokenRefreshedEventEmitter.emit("tokenRefreshed", { | ||
| token: resp.token, | ||
| refreshToken: resp.refreshToken, | ||
| }); | ||
| if (this.refreshPromise) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice dedup logic. Yes this should address the multiple async calls to 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.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, it's definitely not consistent. I was able to reproduce it a few (rare) times by lowering the expiration time of the token, and then switching between the settings and chat tabs. Although I am not 100% sure if it is the problem stated in #110 From my testing, my understanding is that it is possible for either caller_A or caller_B to bug out in the current session. For example, caller_A and caller_B calls
|
||
| return this.refreshPromise; | ||
| } | ||
|
|
||
| this.refreshPromise = (async () => { | ||
| try { | ||
| const response = await this.axiosInstance.post<JsonValue>("/auth/refresh", { | ||
| refreshToken: this.refreshToken, | ||
| }); | ||
| const resp = fromJson(RefreshTokenResponseSchema, response.data); | ||
| this.setTokens(resp.token, resp.refreshToken); | ||
| this.onTokenRefreshedEventEmitter.emit("tokenRefreshed", { | ||
| token: resp.token, | ||
| refreshToken: resp.refreshToken, | ||
| }); | ||
| } finally { | ||
| this.refreshPromise = null; | ||
| } | ||
| })(); | ||
|
|
||
| return this.refreshPromise; | ||
| } | ||
|
|
||
| private async requestWithRefresh(config: AxiosRequestConfig): Promise<JsonValue> { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May i check if im understanding the situation right. This fix is for
401error?In particular, when we refresh due to
401error from sending a request with expired tokens, we get the new generated tokens but this was never updated toauth-store(browserlocalStorage). And so, on the next session, e.g. page reload,auth-storeloads stale tokens leading to401token expiry error?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that's my understanding at least