Problem
The constant REDIRECT_PATH_KEY = "surfsense_redirect_path" is defined privately at surfsense_web/lib/auth-utils.ts:5 and used by getAndClearRedirectPath(), handleUnauthorized(), and redirectToLogin().
But two callers bypass the auth module and write the same key as a magic string:
surfsense_web/app/(home)/login/page.tsx:36
if (returnUrl) {
localStorage.setItem("surfsense_redirect_path", decodeURIComponent(returnUrl));
}
surfsense_web/app/invite/[invite_code]/page.tsx:128
localStorage.setItem("surfsense_redirect_path", `/invite/${inviteCode}`);
If someone renames the key inside auth-utils.ts, login + invite flows silently break — the auth module's storage interface is leaky.
Files
surfsense_web/lib/auth-utils.ts (constant currently private)
surfsense_web/app/(home)/login/page.tsx (line 36)
surfsense_web/app/invite/[invite_code]/page.tsx (line 128)
What to do
- In
auth-utils.ts, add and export a small helper:
export function setRedirectPath(path: string): void {
if (typeof window === "undefined") return;
localStorage.setItem(REDIRECT_PATH_KEY, path);
}
- Replace the two
localStorage.setItem("surfsense_redirect_path", ...) call sites with setRedirectPath(...) (importing from @/lib/auth-utils).
- Verify behavior in both flows:
- Login with
?returnUrl=/dashboard/foo → after Google OAuth, lands on /dashboard/foo
- Open
/invite/<code> → click sign-in → after login, lands back on /invite/<code>
Why this matters
- Locality: storage policy lives in one place — the auth module owns all the redirect-path state transitions.
- Test surface: one helper to test instead of 3 setters scattered across routes.
- Future-proof: when we add an Electron-specific redirect strategy or want to scope by tab, there's one site to change.
Acceptance criteria
Difficulty
Good first issue — small, mechanical, well-scoped.
Problem
The constant
REDIRECT_PATH_KEY = "surfsense_redirect_path"is defined privately atsurfsense_web/lib/auth-utils.ts:5and used bygetAndClearRedirectPath(),handleUnauthorized(), andredirectToLogin().But two callers bypass the auth module and write the same key as a magic string:
surfsense_web/app/(home)/login/page.tsx:36surfsense_web/app/invite/[invite_code]/page.tsx:128If someone renames the key inside
auth-utils.ts, login + invite flows silently break — the auth module's storage interface is leaky.Files
surfsense_web/lib/auth-utils.ts(constant currently private)surfsense_web/app/(home)/login/page.tsx(line 36)surfsense_web/app/invite/[invite_code]/page.tsx(line 128)What to do
auth-utils.ts, add and export a small helper:localStorage.setItem("surfsense_redirect_path", ...)call sites withsetRedirectPath(...)(importing from@/lib/auth-utils).?returnUrl=/dashboard/foo→ after Google OAuth, lands on/dashboard/foo/invite/<code>→ click sign-in → after login, lands back on/invite/<code>Why this matters
Acceptance criteria
setRedirectPathexported fromauth-utils.ts"surfsense_redirect_path"literal anywhere outsideauth-utils.tsreturnUrlredirect still worksDifficulty
Good first issue — small, mechanical, well-scoped.