🔒 Improve token handling in TokenActor: retry on failure and clear pr…#87
Merged
bitbacchus merged 1 commit intomainfrom Jun 6, 2025
Merged
🔒 Improve token handling in TokenActor: retry on failure and clear pr…#87bitbacchus merged 1 commit intomainfrom
bitbacchus merged 1 commit intomainfrom
Conversation
bitbacchus
added a commit
that referenced
this pull request
Jun 6, 2025
* Hotfix Can only click on stats detaiils when availible (#85) * update dependencies * adds loading spinner to dashboard * Hotfix: Stats details can only be clicked when stats avail. * Revert "Hotfix Can only click on stats detaiils when availible (#85)" (#86) This reverts commit 80a01a1. * Delete .github/workflows/deploy-check.yml Updated for Docker deployment Logrotate function explicitly returns 0 now. * 🔒 Improve token handling in TokenActor: retry on failure and clear previous timeout (#87) * Update deploy-test.yml * Version 1.6.2
bitbacchus
added a commit
that referenced
this pull request
Jun 10, 2025
…ization (#89) * PR version 1.6.2 (#88) * Hotfix Can only click on stats detaiils when availible (#85) * update dependencies * adds loading spinner to dashboard * Hotfix: Stats details can only be clicked when stats avail. * Revert "Hotfix Can only click on stats detaiils when availible (#85)" (#86) This reverts commit 80a01a1. * Delete .github/workflows/deploy-check.yml Updated for Docker deployment Logrotate function explicitly returns 0 now. * 🔒 Improve token handling in TokenActor: retry on failure and clear previous timeout (#87) * Update deploy-test.yml * Version 1.6.2 * 🩹 fix(Root): defer auth cookie check to useEffect after actor initialization - Move the inline → redirect out of the render path - Perform the login‐redirect in a that runs once after - Prevents spurious redirects on re‐renders (e.g. when using React DevTools “pause”)
bitbacchus
added a commit
that referenced
this pull request
Jun 11, 2025
* Hotfix Can only click on stats detaiils when availible (#85) * update dependencies * adds loading spinner to dashboard * Hotfix: Stats details can only be clicked when stats avail. * Revert "Hotfix Can only click on stats detaiils when availible (#85)" (#86) This reverts commit 80a01a1. * Create deploy-test.yml * Update deploy-test.yml * Update deploy-test.yml * Update deploy-test.yml * Delete .github/workflows/deploy-check.yml * Update deployment.sh Updated for Docker deployment * Update deployment.sh Logrotate function explicitly returns 0 now. * 🔒 Improve token handling in TokenActor: retry on failure and clear previous timeout (#87) * Update deploy-test.yml * Update deploy-test.yml * Update deployment.sh * Version 1.6.2 * version 1.6.2 * 🐛 fix(Root): defer auth cookie check to useEffect after actor initialization (#89) * PR version 1.6.2 (#88) * Hotfix Can only click on stats detaiils when availible (#85) * update dependencies * adds loading spinner to dashboard * Hotfix: Stats details can only be clicked when stats avail. * Revert "Hotfix Can only click on stats detaiils when availible (#85)" (#86) This reverts commit 80a01a1. * Delete .github/workflows/deploy-check.yml Updated for Docker deployment Logrotate function explicitly returns 0 now. * 🔒 Improve token handling in TokenActor: retry on failure and clear previous timeout (#87) * Update deploy-test.yml * Version 1.6.2 * 🩹 fix(Root): defer auth cookie check to useEffect after actor initialization - Move the inline → redirect out of the render path - Perform the login‐redirect in a that runs once after - Prevents spurious redirects on re‐renders (e.g. when using React DevTools “pause”) * 🐛 Feature/prevent question details without data (#90) 🐛 Add ternary operator to conditionally disable question details button * Feature/docker debian slim wkhtmltopdf install (#91) * chore(docker): switch to node:20-slim and install wkhtmltopdf - solves crash during export * Feature/feature/root add spinner on init (#92) * feat(Root): show spinner while initializing and refactor auth redirect * :chore: issues with auto-deploy on the test server * ✨ chore: issues with auto-deploy to testserver * Update deploy-test.yml * ✨ chore: issues with auto-deploy to testserver * version bump
bitbacchus
added a commit
that referenced
this pull request
Jun 23, 2025
* Hotfix Can only click on stats details when available (#85) * update dependencies * adds loading spinner to dashboard * Hotfix: Stats details can only be clicked when stats avail. * Revert "Hotfix Can only click on stats detaiils when availible (#85)" (#86) This reverts commit 80a01a1. * Create deploy-test.yml * Update deploy-test.yml * Update deploy-test.yml * Update deploy-test.yml * Delete .github/workflows/deploy-check.yml * Update deployment.sh Updated for Docker deployment * Update deployment.sh Logrotate function explicitly returns 0 now. * 🔒 Improve token handling in TokenActor: retry on failure and clear previous timeout (#87) * Update deploy-test.yml * Update deploy-test.yml * Update deployment.sh * Version 1.6.2 * version 1.6.2 * 🐛 fix(Root): defer auth cookie check to useEffect after actor initialization (#89) * PR version 1.6.2 (#88) * Hotfix Can only click on stats detaiils when availible (#85) * update dependencies * adds loading spinner to dashboard * Hotfix: Stats details can only be clicked when stats avail. * Revert "Hotfix Can only click on stats detaiils when availible (#85)" (#86) This reverts commit 80a01a1. * Delete .github/workflows/deploy-check.yml Updated for Docker deployment Logrotate function explicitly returns 0 now. * 🔒 Improve token handling in TokenActor: retry on failure and clear previous timeout (#87) * Update deploy-test.yml * Version 1.6.2 * 🩹 fix(Root): defer auth cookie check to useEffect after actor initialization - Move the inline → redirect out of the render path - Perform the login‐redirect in a that runs once after - Prevents spurious redirects on re‐renders (e.g. when using React DevTools “pause”) * 🐛 Feature/prevent question details without data (#90) 🐛 Add ternary operator to conditionally disable question details button * Feature/docker debian slim wkhtmltopdf install (#91) * chore(docker): switch to node:20-slim and install wkhtmltopdf - solves crash during export * Feature/feature/root add spinner on init (#92) * feat(Root): show spinner while initializing and refactor auth redirect * :chore: issues with auto-deploy on the test server * ✨ chore: issues with auto-deploy to testserver * Update deploy-test.yml * ✨ chore: issues with auto-deploy to testserver * version bump * 🐛 fix(authRefresh): break infinite refresh loop by returning exipry timestamp (#94) * 🐛 fix(authRefresh): break infinite refresh loop by returning expiry timestamp * version bump
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In the previous implementation, we were polling the refresh endpoint at a fixed 1-minute interval regardless of when the access token actually expired. Concretely:
After login, we scheduled a recurring job (e.g. via scheduleRecurring(unit(minutes(1)), …)) to hit /auth/refresh every 60 seconds.
The access token itself had a 5-minute lifetime, but because our refresh job ran on a rigid 1-minute cadence, there was a risk that a network hiccup or timer drift would push the next /auth/refresh call out past the actual expiry time (e.g. calling at 14:01:27 when the token expired at 14:01:26).
If that happened, the token would already be invalid by the time the client called refresh, leading to a gap in which the frontend held a stale (expired) access token, causing 401 errors and unexpected logouts.
Users reported intermittent “timeout” or forced re-login errors. Examining the logs showed lines like:
Setting expiry to 2025-06-03T11:01:26.000Z 2025-06-03T11:26:26.000Z
… (minutes of pings, but no refresh)
GET /auth/refresh? 401 (because it was already past 11:01:26)
Polling every 60 s failed to guarantee “always before expiry,” especially under throttled conditions or slight timer drift.
Solution
We switch from “fixed-interval polling” to “dynamic scheduling based on the actual
expiresAttimestamp.” The main changes are:Capture
expiresAtexactly from the backend’s login/refresh response.expiresAtvalue that the backend logs (or returns) when it issues a new access token.Date(viaitu-utils) so we know precisely how many milliseconds remain until expiry.Use a one-time
setTimeout()(rather thansetInterval()) that fires just before real expiration.As soon as we get a new access token with
exp = <tokenExp>, we compute:Then we call:
In other words, instead of issuing
/auth/refreshevery 60 s, we schedule exactly one callback at(expiresAt − 30 s).On refresh, repeat the above logic with the newly returned
expiresAt.triggerRefresh()hits/auth/refreshand receives a new access token, we again read itsexpiresAttimestamp and schedule the nextsetTimeout()relative to that./auth/refreshtakes extra time (network hiccup) or the frontend’s event loop was delayed—the call still happens before the real token expiry (thanks to the 30 s safety margin).Cancel any leftover timers when refreshing or logging out.
clearTimeout()on the pending timer handle. This prevents stale callbacks from firing after we no longer hold a valid token.Summary of Changes
Removed
Added
In the refresh callback (triggerRefresh()), parsing the new expiresAt from refreshResponse and calling scheduleRefresh(newExpiry) again—ensuring a continuous “refresh-just-before-expiry” loop instead of a blind 60 s interval.
Logic to clear any pending refreshTimeoutHandle on logout or when scheduling a new refresh.
Why it works:
We compute timeoutDuration = (expiresAt − now − 30 s).
Even if the browser is throttled or the network is slow, that 30 s window guarantees we still call /auth/refresh before the token truly expires.
Once the backend issues a new token, it sends back its own expiresAt, which we immediately use to schedule the next refresh.