more auth ree
This commit is contained in:
@@ -4,7 +4,6 @@ import {
|
||||
Outlet,
|
||||
Scripts,
|
||||
createRootRouteWithContext,
|
||||
redirect,
|
||||
} from "@tanstack/react-router";
|
||||
import * as React from "react";
|
||||
import { DefaultCatchBoundary } from "@/components/DefaultCatchBoundary";
|
||||
@@ -133,15 +132,6 @@ export const Route = createRootRouteWithContext<{
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (error instanceof Response && error.status === 440) {
|
||||
console.log('__root beforeLoad: Session needs refresh, redirecting');
|
||||
const from = encodeURIComponent(location.pathname + location.search);
|
||||
throw redirect({
|
||||
to: "/refresh-session",
|
||||
search: { redirect: from }
|
||||
});
|
||||
}
|
||||
|
||||
console.error('__root beforeLoad error:', error);
|
||||
return {};
|
||||
}
|
||||
@@ -152,6 +142,32 @@ export const Route = createRootRouteWithContext<{
|
||||
function RootComponent() {
|
||||
React.useEffect(() => {
|
||||
ensureSuperTokensFrontend();
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
const cookies = document.cookie.split(';');
|
||||
const accessTokenCookies = cookies.filter(c => c.trim().startsWith('sAccessToken='));
|
||||
|
||||
if (accessTokenCookies.length > 1) {
|
||||
console.warn(`[Root] Found ${accessTokenCookies.length} duplicate sAccessToken cookies - clearing all SuperTokens cookies`);
|
||||
|
||||
const cookieNames = ['sAccessToken', 'sRefreshToken', 'sIdRefreshToken', 'sFrontToken'];
|
||||
const cookieDomain = (window as any).__COOKIE_DOMAIN__ || undefined;
|
||||
|
||||
cookieNames.forEach(name => {
|
||||
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||||
|
||||
if (cookieDomain) {
|
||||
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${cookieDomain}`;
|
||||
}
|
||||
});
|
||||
|
||||
console.log('[Root] Cleared duplicate cookies - page will reload to establish fresh session');
|
||||
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
@@ -56,21 +56,8 @@ export const fetchMe = createServerFn()
|
||||
}
|
||||
|
||||
if (error?.message === "SESSION_REFRESH_REQUIRED") {
|
||||
logger.info("FetchMe: Session refresh required (server function)");
|
||||
throw new Response(
|
||||
JSON.stringify({
|
||||
error: "SESSION_REFRESH_REQUIRED",
|
||||
message: "Session needs to be refreshed",
|
||||
shouldRetry: true
|
||||
}),
|
||||
{
|
||||
status: 440,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Session-Expired": "true"
|
||||
}
|
||||
}
|
||||
);
|
||||
logger.info("FetchMe: Session refresh required - returning empty auth (client will handle cleanup)");
|
||||
return { user: undefined, roles: [], metadata: {}, phone: undefined };
|
||||
}
|
||||
|
||||
if (error?.message === "Unauthenticated") {
|
||||
|
||||
@@ -10,32 +10,14 @@ 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, cleaning up`);
|
||||
logger.warn(`Detected ${tokens.length} duplicate sAccessToken cookies - session is broken, forcing cleanup`);
|
||||
|
||||
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 });
|
||||
return {
|
||||
hasToken: false,
|
||||
needsRefresh: true,
|
||||
error: 'DUPLICATE_COOKIES_DETECTED',
|
||||
duplicateCount: tokens.length
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ export async function ensureServerQueryData<TData>(
|
||||
if (error?.options?.to && error?.options?.statusCode) {
|
||||
throw error;
|
||||
}
|
||||
if (error instanceof Response && error.status === 440) {
|
||||
throw error;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,6 @@ export const toServerResult = async <T>(
|
||||
}
|
||||
}
|
||||
|
||||
if (error instanceof Response && error.status === 440) {
|
||||
logger.info('toServerResult: Re-throwing 440 Response for session refresh');
|
||||
throw error;
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
logger.error('Server Fn Error', error);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user