diff --git a/src/lib/supertokens/recipes/start-session.ts b/src/lib/supertokens/recipes/start-session.ts index 8f2a5f5..66d7b5b 100644 --- a/src/lib/supertokens/recipes/start-session.ts +++ b/src/lib/supertokens/recipes/start-session.ts @@ -10,14 +10,32 @@ export async function getSessionForStart(request: Request, options?: { sessionRe if (cookieHeader) { const tokens = cookieHeader.match(/sAccessToken=([^;]+)/g); if (tokens && tokens.length > 1) { - logger.warn(`Detected ${tokens.length} duplicate sAccessToken cookies - session is broken, forcing cleanup`); + logger.warn(`Detected ${tokens.length} duplicate sAccessToken cookies, cleaning up`); - return { - hasToken: false, - needsRefresh: true, - error: 'DUPLICATE_COOKIES_DETECTED', - duplicateCount: tokens.length - }; + const parsedTokens = tokens.map(tokenStr => { + const token = tokenStr.replace('sAccessToken=', ''); + try { + const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); + return { token, exp: payload.exp, iat: payload.iat }; + } catch (e) { + logger.error('Failed to parse token', e); + return { token, exp: 0, iat: 0 }; + } + }); + + parsedTokens.sort((a, b) => b.exp - a.exp); + const freshestToken = parsedTokens[0]; + + logger.info(`Using freshest token: exp=${freshestToken.exp}, iat=${freshestToken.iat}`); + + const cleanedCookie = cookieHeader + .split(';') + .filter(c => !c.trim().startsWith('sAccessToken=')) + .join(';') + `; sAccessToken=${freshestToken.token}`; + + const cleanedHeaders = new Headers(request.headers); + cleanedHeaders.set('cookie', cleanedCookie); + request = new Request(request, { headers: cleanedHeaders }); } } diff --git a/src/utils/supertokens.ts b/src/utils/supertokens.ts index bddc582..7dc158e 100644 --- a/src/utils/supertokens.ts +++ b/src/utils/supertokens.ts @@ -55,11 +55,17 @@ export const getSessionContext = createServerOnlyFn(async (request: Request, opt if (options?.isServerFunction) { throw new Error("SESSION_REFRESH_REQUIRED"); } - + const url = new URL(request.url); + + if (url.pathname === '/refresh-session') { + logger.warn("Already on refresh-session page but session needs refresh - treating as unauthenticated"); + throw new Error("Unauthenticated"); + } + const from = encodeURIComponent(url.pathname + url.search); - throw redirect({ - to: "/refresh-session", + throw redirect({ + to: "/refresh-session", search: { redirect: from } }); }