fix(auth): never persist refresh token to localStorage; rely on httpOnly cookie (Closes #898) - #926
Merged
Topmatrixmor2014 merged 1 commit intoAug 26, 2026
Conversation
…nly cookie (Closes FinChippay#898)
🤖 Greptile AI Code ReviewGreptile will automatically review this PR (3 file(s) changed). Review gates:
|
| }); | ||
|
|
||
| describe("auth refresh flow via httpOnly cookie", () => { | ||
| const API_URL = "http://localhost:4000"; |
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.
Closes #898
Problem
The backend already sets the refresh token as an
httpOnly,SameSite=strictcookie, but the frontend still referenced afinchippay_refresh_tokenlocalStorage key in several auth/wallet code paths. Any XSS could exfiltrate a token stored in localStorage, undermining exactly what the httpOnly cookie was designed to prevent.Fix
frontend/lib/auth.ts:getRefreshToken/setRefreshToken/clearJwtTokennow only track a booleanfinchippay_has_sessionsession flag — the actual refresh token is never written to localStorage. Token refresh rides the backend httpOnly cookie viacredentials: "include"on/api/auth/refresh.frontend/lib/wallet.ts: removed the redundantfinchippay_refresh_tokenlocalStorage cleanup indisconnectWallet(logout already clears viaclearAuthToken).setRefreshToken/clearJwtTokenstill purge any legacy residualfinchippay_refresh_tokenkey left by earlier versions, so upgrading cleans old insecure data.Tests
Added
__tests__/auth.test.ts(8 tests) covering:clearJwtTokenremoves the session flag and purges residual keys./api/auth/refreshis called withcredentials: "include"and never sends the token as header/body.withAuthpreemptively refreshes via the cookie when only a session flag exists.All 8 tests pass.