Fix session persistence - improve token restoration

cgen-47838b8ee0e941d4845ff07ce0b2a7fd
This commit is contained in:
Builder.io 2025-11-05 02:36:14 +00:00
parent e3f4f06a9c
commit dea4a6c9ed

View file

@ -165,11 +165,15 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
const storageClearedRef = useRef(false); const storageClearedRef = useRef(false);
useEffect(() => { useEffect(() => {
let sessionRestored = false;
// Add timeout to ensure loading doesn't get stuck // Add timeout to ensure loading doesn't get stuck
const loadingTimeout = setTimeout(() => { const loadingTimeout = setTimeout(() => {
console.log("Auth loading timeout - forcing loading to false"); console.log("Auth loading timeout - forcing loading to false");
setLoading(false); if (!sessionRestored) {
}, 5000); setLoading(false);
}
}, 8000);
if (!storageClearedRef.current && typeof window !== "undefined") { if (!storageClearedRef.current && typeof window !== "undefined") {
try { try {
@ -189,29 +193,51 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
} }
} }
// Get initial session // Helper to check if auth tokens exist in localStorage
supabase.auth const hasAuthTokens = () => {
.getSession() if (typeof window === "undefined") return false;
.then(({ data: { session } }) => { const keys = Object.keys(window.localStorage);
clearTimeout(loadingTimeout); return keys.some((key) => key.includes("auth-token") || key.includes("sb-") && key.includes("-auth"));
setSession(session); };
setUser(session?.user ?? null);
// Get initial session with persistence recovery
const initializeAuth = async () => {
try {
const { data: { session } } = await supabase.auth.getSession();
// If no session but tokens exist, the session might not have restored yet
// Wait a bit for onAuthStateChange to trigger
if (!session && hasAuthTokens()) {
console.log("Tokens exist in storage but session not yet restored, waiting...");
// Don't set loading to false yet - wait for onAuthStateChange
return;
}
if (session?.user) { if (session?.user) {
fetchUserProfile(session.user.id); sessionRestored = true;
setSession(session);
setUser(session.user);
await fetchUserProfile(session.user.id);
} else { } else {
sessionRestored = true;
setLoading(false); setLoading(false);
} }
}) } catch (error) {
.catch((error) => {
clearTimeout(loadingTimeout);
console.error("Error getting session:", error); console.error("Error getting session:", error);
sessionRestored = true;
setLoading(false); setLoading(false);
}); }
};
// Listen for auth changes initializeAuth();
// Listen for auth changes - this is the source of truth
const { const {
data: { subscription }, data: { subscription },
} = supabase.auth.onAuthStateChange(async (event, session) => { } = supabase.auth.onAuthStateChange(async (event, session) => {
console.log("Auth state change:", event, !!session?.user);
sessionRestored = true;
setSession(session); setSession(session);
setUser(session?.user ?? null); setUser(session?.user ?? null);
@ -220,8 +246,8 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
} else { } else {
setProfile(null); setProfile(null);
setRoles([]); setRoles([]);
setLoading(false);
} }
setLoading(false);
// Handle token refresh failures specifically // Handle token refresh failures specifically
if (event === "TOKEN_REFRESH_FAILED") { if (event === "TOKEN_REFRESH_FAILED") {
@ -257,7 +283,10 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
} }
}); });
return () => subscription.unsubscribe(); return () => {
clearTimeout(loadingTimeout);
subscription.unsubscribe();
};
}, []); }, []);
const fetchUserProfile = async ( const fetchUserProfile = async (