mirror of https://github.com/buster-so/buster.git
Fix session expiration issues
- Fix anonymous user token validation boolean logic - Add background token refresh mechanism for idle sessions - Improve WebSocket token refresh error handling - Ensure robust session persistence for long-running sessions Co-Authored-By: nate@buster.so <nate@buster.so>
This commit is contained in:
parent
a369ba2b32
commit
5bb8034e2c
|
@ -20,6 +20,7 @@ const useSupabaseContextInternal = ({
|
|||
supabaseContext: UseSupabaseUserContextType;
|
||||
}) => {
|
||||
const refreshTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
const backgroundRefreshRef = useRef<ReturnType<typeof setInterval> | undefined>(undefined);
|
||||
const { openErrorNotification, openInfoMessage } = useBusterNotifications();
|
||||
const [accessToken, setAccessToken] = useState(supabaseContext.accessToken || '');
|
||||
|
||||
|
@ -42,7 +43,7 @@ const useSupabaseContextInternal = ({
|
|||
if (isAnonymousUser) {
|
||||
return {
|
||||
access_token: accessToken,
|
||||
isTokenValid: isTokenExpired
|
||||
isTokenValid: !isTokenExpired
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -122,6 +123,26 @@ const useSupabaseContextInternal = ({
|
|||
};
|
||||
}, [accessToken, checkTokenValidity]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAnonymousUser) return;
|
||||
|
||||
const BACKGROUND_CHECK_INTERVAL = 4 * 60 * 1000;
|
||||
|
||||
backgroundRefreshRef.current = setInterval(async () => {
|
||||
try {
|
||||
await checkTokenValidity();
|
||||
} catch (error) {
|
||||
console.error('Background token refresh failed:', error);
|
||||
}
|
||||
}, BACKGROUND_CHECK_INTERVAL);
|
||||
|
||||
return () => {
|
||||
if (backgroundRefreshRef.current) {
|
||||
clearInterval(backgroundRefreshRef.current);
|
||||
}
|
||||
};
|
||||
}, [isAnonymousUser, checkTokenValidity]);
|
||||
|
||||
return {
|
||||
isAnonymousUser,
|
||||
setAccessToken,
|
||||
|
|
|
@ -134,7 +134,16 @@ const useWebSocket = ({ url, checkTokenValidity, canConnect, onMessage }: WebSoc
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Generic data type for WebSocket messages
|
||||
const sendJSONMessage = useMemoizedFn(async (data: Record<string, any>, isFromQueue = false) => {
|
||||
await checkTokenValidity(); //needed! This will refresh the token if it is expired. All other messages will be queued until the token is refreshed.
|
||||
try {
|
||||
await checkTokenValidity(); //needed! This will refresh the token if it is expired. All other messages will be queued until the token is refreshed.
|
||||
} catch (error) {
|
||||
console.error('Token validation failed before sending WebSocket message:', error);
|
||||
if (!isFromQueue) {
|
||||
sendQueue.current.push(data); // Queue the message for retry
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ws.current?.readyState === ReadyState.Closed) {
|
||||
connectWebSocket();
|
||||
}
|
||||
|
@ -165,7 +174,11 @@ const useWebSocket = ({ url, checkTokenValidity, canConnect, onMessage }: WebSoc
|
|||
// Use fetch to check connection first and get headers
|
||||
checkTokenValidity()
|
||||
.then(({ access_token, isTokenValid }) => {
|
||||
if (!isTokenValid) return;
|
||||
if (!isTokenValid) {
|
||||
console.warn('Token is invalid, skipping WebSocket connection');
|
||||
setConnectionError('Invalid authentication token');
|
||||
return;
|
||||
}
|
||||
// If fetch succeeds, establish WebSocket connection
|
||||
const socketURLWithAuth = `${url}?authentication=${access_token}`;
|
||||
ws.current = new WebSocket(socketURLWithAuth);
|
||||
|
@ -173,7 +186,7 @@ const useWebSocket = ({ url, checkTokenValidity, canConnect, onMessage }: WebSoc
|
|||
})
|
||||
.catch((error) => {
|
||||
console.error('Connection error:', error);
|
||||
setConnectionError(error.message);
|
||||
setConnectionError(error.message || 'Authentication failed');
|
||||
});
|
||||
}),
|
||||
{ wait: BASE_DELAY }
|
||||
|
|
Loading…
Reference in New Issue