// Shared client-side auth helpers. // // The session lives entirely in httpOnly cookies that the server sets at // /api/auth/callback, so there are no tokens for the page to store or read. // We just send the cookies with every request and recover from access-token // expiry by silently refreshing once before giving up and sending the user // back through Google. function redirectToLogin() { window.location.href = "/api/auth/login"; } // fetch() wrapper that always sends the session cookies. On a 401 it attempts // a single silent refresh (the refresh cookie is scoped to /api/auth) and // retries the original request; if that still fails, it bounces to login. async function authedFetch(url, options = {}) { const opts = { credentials: "include", ...options }; let res = await fetch(url, opts); if (res.status !== 401) return res; const refreshed = await fetch("/api/auth/refresh", { method: "POST", credentials: "include", }); if (refreshed.ok) { res = await fetch(url, opts); if (res.status !== 401) return res; } redirectToLogin(); throw new Error("Not authenticated"); }