From cffca379997ec73b70a0c9fcfc1a83b83de8f3d0 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Thu, 27 Nov 2025 12:30:48 +0000 Subject: [PATCH] FS: Check session expiration and rotate if needed (#114433) * FS: Check session expiration and rotate if needed * Remove unused return values --- pkg/services/frontend/index.html | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pkg/services/frontend/index.html b/pkg/services/frontend/index.html index 2eb4d82dce3..0a589f81a49 100644 --- a/pkg/services/frontend/index.html +++ b/pkg/services/frontend/index.html @@ -239,6 +239,30 @@ const CHECK_INTERVAL = 1 * 1000; + function getCookie(name) { + const cookies = document.cookie.split(";").map(c => c.trim()); + + for (const cookie of cookies) { + if (cookie.startsWith(name + "=")) { + return cookie.substring(name.length + 1); + } + } + + return null; + } + + function getSessionExpiration() { + const value = getCookie("grafana_session_expiry") || "0"; + const realExpiresSeconds = parseInt(value, 10); + const expiresSeconds = Math.max(realExpiresSeconds - 10, 0); // Rotate 10s before the real expiration + const expiration = new Date(expiresSeconds * 1000); + return expiration; + } + + async function rotateSession() { + await fetch('/api/user/auth-tokens/rotate', { method: 'POST' }); + } + /** * Fetches boot data from the server. If it returns undefined, it should be retried later. * Will return a rejected promise on unrecoverable errors. @@ -295,6 +319,19 @@ function loadBootData() { return new Promise((resolve, reject) => { const attemptFetch = async () => { + try { + const sessionExpiration = getSessionExpiration(); + const now = new Date(); + + // If the session has expired, don't continue trying to fetch boot data + if (now >= sessionExpiration) { + await rotateSession(); + } + } catch (error) { + // Just ignore any errors in session rotation. The user can just log in again. + console.warn("Failed to rotate session", error); + } + try { const bootData = await fetchBootData();