Skip to content

Improve token refresh experience#10007

Open
BacLuc wants to merge 2 commits into
ecamp:develfrom
BacLuc:improve-refresh-further
Open

Improve token refresh experience#10007
BacLuc wants to merge 2 commits into
ecamp:develfrom
BacLuc:improve-refresh-further

Conversation

@BacLuc

@BacLuc BacLuc commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

refresh_token: retry requests to the api after refreshing the auth token

Issue: #8950


frontend: if the token refresh doesn't work, allow the user to login in another tab

This also supports oauth and keeps the state the user was in.
Also do not route to the login page as long as we don't know if
we need to authenticate or not.

Issue: ecamp#8950

Signed-off-by: BacLuc <lucius.bachmann@clubpage.ch>
@BacLuc

BacLuc commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

…in another tab

This also supports oauth and keeps the state the user was in.
Also do not route to the login page as long as we don't know if
we need to authenticate or not.

Signed-off-by: BacLuc <lucius.bachmann@clubpage.ch>
@BacLuc
BacLuc force-pushed the improve-refresh-further branch from c1a30c7 to c6c0cd3 Compare June 14, 2026 20:17
@BacLuc
BacLuc marked this pull request as ready for review June 14, 2026 20:17
@BacLuc
BacLuc requested a review from a team June 14, 2026 20:18
@BacLuc BacLuc changed the title Improve refresh further Improve token refresh experience Jun 14, 2026
@BacLuc
BacLuc requested a review from a team June 20, 2026 20:54

@carlobeltrame carlobeltrame left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to read through this and make sense of it, but it's too complex to wrap my head around in a reasonable amount of time. Do you @BacLuc @pmattmann understand all of this and see justification for every line? For my part, I am not comfortable with having AI-generated code in this order of complexity for something as essential as the login state of the application. In line with our at-least-one-approval policy, I think at least two members of the core team should really understand what's going on here before merging. IMO, documentation and unit tests are also essential missing parts here.

Feel free to dismiss my review as soon as two members of the core team understand the details of what's going on here and feel comfortable maintaining it.

Comment on lines +14 to +17
let refreshTokenPromise = null
let reAuthPromise = null
let reAuthResolve = null
let reAuthReject = null

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Top-level variables like this make it very hard to write unit tests for this file, and this complex logic definitely deserves unit testing, not just an e2e test which may or may not be marked as immature and mostly ignored in the future.

Also, consider extracting the reAuth logic into a separate file.

Comment on lines +19 to +27
function waitForReAuth() {
if (!reAuthPromise) {
reAuthPromise = new Promise((resolve, reject) => {
reAuthResolve = resolve
reAuthReject = reject
})
}
let refreshedSuccessfully = false
if (!isLoggedIn()) {
return reAuthPromise
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no waiting in here, is the naming correct?

Comment on lines +29 to +43
export function resolveReAuth() {
reAuthResolve?.()
reAuthPromise = null
reAuthResolve = null
reAuthReject = null
store.commit('setAuthRequired', false)
}

export function rejectReAuth() {
reAuthReject?.(new Error('Re-authentication cancelled'))
reAuthPromise = null
reAuthResolve = null
reAuthReject = null
store.commit('setAuthRequired', false)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This all feels a lot like an anti-pattern... There are so many moving parts in this file: The module-level let variables, the flags in the store, the flags in local storage, some custom fields on the request object, the singleton pattern, ...

I think we should first define the target architecture of this feature.

Comment on lines +60 to +66
if (
status !== 401 ||
!request ||
request._authRetried ||
isRefreshRequest(request) ||
hasLoggedOutFromLocalStorage()
) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very hard to understand. Can we use a local variable for this?

Suggested change
if (
status !== 401 ||
!request ||
request._authRetried ||
isRefreshRequest(request) ||
hasLoggedOutFromLocalStorage()
) {
const needsAuthRetry = (status === 401 && request && !request._authRetried && !isRefreshRequest(request) && !hasLoggedOutFromLocalStorage())
if (!needsAuthRetry) {

Comment on lines -24 to +25
const axiosInstance = axios.create({
axiosInstance = axios.create({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this const to a let seems unnecessary, since it's never reassigned..? (the setupAxiosAuthInterceptor cannot reassign it, it can only mutate the argument)

})
}

function refreshAuthTokenSingleton() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In javascript, a singleton would usually be realized as a separate module (js file) exporting the necessary functions and objects. See our plugins for examples, e.g. i18n or slugify or passwordStrength

@BacLuc

BacLuc commented Jul 14, 2026

Copy link
Copy Markdown
Contributor Author

I tried to read through this and make sense of it, but it's too complex to wrap my head around in a reasonable amount of time. Do you @BacLuc @pmattmann understand all of this and see justification for every line? For my part, I am not comfortable with having AI-generated code in this order of complexity for something as essential as the login state of the application. In line with our at-least-one-approval policy, I think at least two members of the core team should really understand what's going on here before merging. IMO, documentation and unit tests are also essential missing parts here.

Feel free to dismiss my review as soon as two members of the core team understand the details of what's going on here and feel comfortable maintaining it.

Thanks for the feedback.
What i would like to know is:
Does it improve the token refresh experience for you?
Are there features missing or unnecessary features or things you would wish they would behave differently?

As soon as we know which features we want we can start split up the thing, improve the code for the single steps and get them in devel one by one. (as long is there is feedback on the way).

@carlobeltrame

Copy link
Copy Markdown
Member

I have not tested it, just tried to read the code so far. The improvements you list in the PR description sound reasonable to me. Not sure whether there is more to be done, I think we both agree that we should collect the use cases first, and I don't yet have them collected. Once we have the use cases and user flows, we can think about an architecture to support them, and then we can implement.

I support the agile approach, doing everything in small steps. But reading this PR, I do not believe that this is the easiest and cleanest way to acheive these features. It does not matter to me if this PR has everything working feature-wise, because in order to acccept a PR, both the functionality and the code must be good enough. So taking a step back and designing a clean architecture before implementing the agile steps might be appropriate here, is what I am saying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants