diff --git a/www/app/lib/SessionAutoRefresh.tsx b/www/app/lib/SessionAutoRefresh.tsx index 9542581e..7d67eee8 100644 --- a/www/app/lib/SessionAutoRefresh.tsx +++ b/www/app/lib/SessionAutoRefresh.tsx @@ -9,22 +9,20 @@ import { useEffect } from "react"; import { useAuth } from "./AuthProvider"; +import { REFRESH_ACCESS_TOKEN_BEFORE } from "./auth"; -export function SessionAutoRefresh({ - children, - refreshInterval = 5 /* seconds */, -}) { +const REFRESH_BEFORE = REFRESH_ACCESS_TOKEN_BEFORE; + +export function SessionAutoRefresh({ children }) { const auth = useAuth(); const accessTokenExpires = auth.status === "authenticated" ? auth.accessTokenExpires : null; - console.log("authauth", auth); - const refreshIntervalMs = refreshInterval * 1000; useEffect(() => { const interval = setInterval(() => { if (accessTokenExpires !== null) { const timeLeft = accessTokenExpires - Date.now(); - if (timeLeft < refreshIntervalMs) { + if (timeLeft < REFRESH_BEFORE) { auth .update() .then(() => {}) @@ -34,10 +32,10 @@ export function SessionAutoRefresh({ }); } } - }, refreshIntervalMs); + }, 5000); return () => clearInterval(interval); - }, [accessTokenExpires, refreshInterval, auth.update]); + }, [accessTokenExpires, auth.update]); return children; } diff --git a/www/app/lib/auth.ts b/www/app/lib/auth.ts index c5d39e75..7764c691 100644 --- a/www/app/lib/auth.ts +++ b/www/app/lib/auth.ts @@ -1 +1,3 @@ export const REFRESH_ACCESS_TOKEN_ERROR = "RefreshAccessTokenError" as const; +// 4 min is 1 min less than default authentic value. here we assume that authentic won't be set to access tokens < 4 min +export const REFRESH_ACCESS_TOKEN_BEFORE = 4 * 60 * 1000; diff --git a/www/app/lib/authBackend.ts b/www/app/lib/authBackend.ts index 10cf3d40..b7150e8c 100644 --- a/www/app/lib/authBackend.ts +++ b/www/app/lib/authBackend.ts @@ -7,15 +7,18 @@ import { assertExistsAndNonEmptyString, parseMaybeNonEmptyString, } from "./utils"; -import { REFRESH_ACCESS_TOKEN_ERROR } from "./auth"; - -const PRETIMEOUT = 600; +import { + REFRESH_ACCESS_TOKEN_BEFORE, + REFRESH_ACCESS_TOKEN_ERROR, +} from "./auth"; +// TODO redis for vercel? const tokenCache = new Map< string, { token: JWTWithAccessToken; timestamp: number } >(); -const TOKEN_CACHE_TTL = 60 * 60 * 24 * 30 * 1000; // 30 days in milliseconds +// REFRESH_ACCESS_TOKEN_BEFORE because refresh is based on access token expiration (imagine we cache it 30 days) +const TOKEN_CACHE_TTL = REFRESH_ACCESS_TOKEN_BEFORE; const refreshLocks = new Map>(); @@ -49,7 +52,7 @@ export const authOptions: AuthOptions = { if (account && user) { // called only on first login // XXX account.expires_in used in example is not defined for authentik backend, but expires_at is - const expiresAtS = assertExists(account.expires_at) - PRETIMEOUT; + const expiresAtS = assertExists(account.expires_at); const expiresAtMs = expiresAtS * 1000; if (!account.access_token) { tokenCache.delete(KEY); @@ -165,8 +168,7 @@ async function refreshAccessToken(token: JWT): Promise { return { ...token, accessToken: refreshedTokens.access_token, - accessTokenExpires: - Date.now() + (refreshedTokens.expires_in - PRETIMEOUT) * 1000, + accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000, refreshToken: refreshedTokens.refresh_token, }; } catch (error) {