client/web: signal need to wait for auth across tabs

This implements a signaling mechanism that indicates the need to
call the auth/session/wait endpoint when returning to the app (in
any tab). We try to open the auth URL in a new tab so that
auth/session/wait can be called once the current tab regains focus.
However, it might open in the same tab based on browser settings,
thus foregoing the subsequent call to auth/session/wait.

Fixes #11905

Signed-off-by: Gesa Stupperich <gesa@tailscale.com>
gesa/device-ui-bug
Gesa Stupperich 2 months ago
parent 005e264b54
commit c134fdc817

@ -81,7 +81,25 @@ export default function useAuth() {
return apiFetch<{ authUrl?: string }>("/auth/session/new", "GET")
.then((d) => {
if (d.authUrl) {
// Store a flag to signal that auth is in progress.
// We try to open the auth URL in a new tab, but it might open
// in the same tab depending on browser settings
// (https://github.com/tailscale/tailscale/issues/11905).
// The flag will be used when returning to the app (in any tab).
localStorage.setItem("ts-web-needs-auth-wait", "true")
// Open the auth URL - this might open in a new tab or
// replace the current tab depending on browser settings.
window.open(d.authUrl, "_blank")
// If execution continues here, we're still in the original tab
// (the URL opened in a new tab or the popup was blocked).
// If it opened in the same tab, we'll handle this when the user
// returns via the effect that checks for the pending auth flag.
// If it opened in a new tab, we can wait for auth to complete now.
// (If the popup was blocked, we'll also wait here.)
// Wait for the auth session to complete.
return apiFetch("/auth/session/wait", "GET")
}
})
@ -115,6 +133,23 @@ export default function useAuth() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ranSynoAuth])
// Handle returning to the UI after having completed the auth flow in any tab.
useEffect(() => {
// Check if we have a pending auth session when the component mounts.
const pendingAuth = localStorage.getItem("ts-web-needs-auth-wait")
if (pendingAuth === "true") {
localStorage.removeItem("ts-web-needs-auth-wait")
// Wait for the auth session to complete.
apiFetch("/auth/session/wait", "GET")
.then(() => {
loadAuth()
})
.catch((error) => {
console.error(error)
})
}
}, [loadAuth])
return {
data,
loading,

Loading…
Cancel
Save