fix(server/web): SPA navigate() to backend bridge URLs renders 404

When the desktop one-click login flow opens
  /heicode/oauth/authorize?state=...&redirect_uri=...
in the browser and the user isn't signed in, Manager renders the
"please log in" bridge page that links to /sign-in?redirect=<authUrl>.
After login, useAuthRedirect's `handleLoginSuccess` calls TanStack
Router's `navigate({ to: targetPath })` to send the user back to
that authorize URL.

But TanStack Router only knows about React routes; backend bridges
(`/heicode/oauth/...`, `/api/...`) have no matching route, so the
SPA renders 404. The user has to manually re-enter the URL, at
which point the backend handles it and 302s to the loopback
callback. This produced the 500 → 404 → success symptom users hit
on first-time desktop login.

Fix: detect backend prefixes (`/heicode/oauth/`, `/api/`) and use
`window.location.assign()` to force a full-page navigation so the
server gets the request directly. React-route paths still go
through `navigate()` as before.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-09 17:29:01 +08:00
co-authored by Claude Opus 4.7
parent 6ca8bf42d6
commit 6cc981d366
@@ -129,11 +129,34 @@ export function useAuthRedirect() {
// 告知路由守卫:本会话已完成登录,避免 beforeLoad 再次请求 /me 失败导致踢回登录页
markHeicodeAuthenticatedSessionVerified()
// Navigate to target page
// Navigate to target page.
//
// Tricky bit: the SPA's `navigate()` only knows about TanStack-Router
// routes; if `redirectTo` points at a backend bridge URL like
// `/heicode/oauth/authorize?...` (set by the desktop one-click login
// flow — see `heicode/controller/heicode_oauth.go:renderHeicodeLoginRequired`),
// the router renders 404 because no React route matches. The user
// then has to manually re-enter the URL, at which point the backend
// handles it and 302s to the loopback callback.
//
// Detect known backend prefixes and force a full-page navigation
// (window.location.assign) so the server gets the request directly.
const targetPath = normalizeRedirectTarget(redirectTo)
if (isBackendBridgePath(targetPath)) {
window.location.assign(targetPath)
return
}
navigate({ to: targetPath, replace: true })
}
// Paths under these prefixes are served by the Go backend (oauth bridge,
// file downloads, etc.) and have NO matching React route. Navigating to
// them via TanStack `navigate()` would render the SPA's 404.
const BACKEND_BRIDGE_PREFIXES = ['/heicode/oauth/', '/api/']
function isBackendBridgePath(path: string): boolean {
return BACKEND_BRIDGE_PREFIXES.some((prefix) => path.startsWith(prefix))
}
/**
* Redirect to 2FA page
*/