This commit is contained in:
pablonyx
2025-03-13 16:09:53 -07:00
parent 38afc8fa3a
commit 81cb98aaa7
4 changed files with 95 additions and 82 deletions

View File

@ -1,6 +0,0 @@
from fastapi import APIRouter
router = APIRouter()
# Add production endpoints here

View File

@ -423,8 +423,7 @@ def get_application() -> FastAPI:
# NOTE: needs to be outside of the `if __name__ == "__main__"` block so that the
# app is exportable
set_is_ee_based_on_env_variable()
# Call get_application() to get the actual application instance
app = fetch_versioned_implementation(module="onyx.main", attribute="get_application")()
app = fetch_versioned_implementation(module="onyx.main", attribute="get_application")
if __name__ == "__main__":

View File

@ -12,6 +12,7 @@ import { getCurrentUser } from "@/lib/user";
import { usePostHog } from "posthog-js/react";
import { CombinedSettings } from "@/app/admin/settings/interfaces";
import { SettingsContext } from "../settings/SettingsProvider";
import { useTokenRefresh } from "@/hooks/useTokenRefresh";
interface UserContextType {
user: User | null;
@ -71,12 +72,6 @@ export function UserProvider({
mergeUserPreferences(user, settings)
);
// Track last refresh time to avoid unnecessary calls
const [lastTokenRefresh, setLastTokenRefresh] = useState<number>(Date.now());
// Use a ref to track first load
const isFirstLoad = useRef(true);
useEffect(() => {
setUpToDateUser(mergeUserPreferences(user, updatedSettings));
}, [user, updatedSettings]);
@ -97,74 +92,6 @@ export function UserProvider({
}
}, [posthog, user]);
// Implement token refresh mechanism
useEffect(() => {
if (!upToDateUser) return;
// Refresh token every 10 minutes (600000ms)
// This is shorter than the session expiry time to ensure tokens stay valid
const REFRESH_INTERVAL = 600000;
const refreshTokenPeriodically = async () => {
try {
// Skip time check if this is first load - we always refresh on first load
const isTimeToRefresh =
isFirstLoad.current ||
Date.now() - lastTokenRefresh > REFRESH_INTERVAL - 60000;
if (!isTimeToRefresh) {
return;
}
// Reset first load flag
if (isFirstLoad.current) {
isFirstLoad.current = false;
}
const response = await fetch("/api/auth/refresh", {
method: "POST",
credentials: "include",
});
if (response.ok) {
// Update last refresh time on success
setLastTokenRefresh(Date.now());
console.debug("Auth token refreshed successfully");
} else {
console.warn("Failed to refresh auth token:", response.status);
// If token refresh fails, try to get current user info
await fetchUser();
}
} catch (error) {
console.error("Error refreshing auth token:", error);
}
};
// Always attempt to refresh on first component mount
// This helps ensure tokens are fresh, especially after browser refresh
refreshTokenPeriodically();
// Set up interval for periodic refreshes
const intervalId = setInterval(refreshTokenPeriodically, REFRESH_INTERVAL);
// Also refresh token on window focus, but no more than once per minute
const handleVisibilityChange = () => {
if (
document.visibilityState === "visible" &&
Date.now() - lastTokenRefresh > 60000
) {
refreshTokenPeriodically();
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () => {
clearInterval(intervalId);
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, [upToDateUser, lastTokenRefresh]);
const fetchUser = async () => {
try {
const currentUser = await getCurrentUser();
@ -173,6 +100,10 @@ export function UserProvider({
console.error("Error fetching current user:", error);
}
};
// Use the custom token refresh hook
useTokenRefresh(upToDateUser, fetchUser);
const updateUserTemperatureOverrideEnabled = async (enabled: boolean) => {
try {
setUpToDateUser((prevUser) => {

View File

@ -0,0 +1,89 @@
import { useState, useEffect, useRef } from "react";
import { User } from "@/lib/types";
/**
* Custom hook for handling JWT token refresh
*
* @param user The current user or null if not logged in
* @param onRefreshFail Callback function to execute if token refresh fails
* @returns Object containing the last token refresh timestamp
*/
export function useTokenRefresh(
user: User | null,
onRefreshFail: () => Promise<void>
) {
// Track last refresh time to avoid unnecessary calls
const [lastTokenRefresh, setLastTokenRefresh] = useState<number>(Date.now());
// Use a ref to track first load
const isFirstLoad = useRef(true);
useEffect(() => {
if (!user) return;
// Refresh token every 10 minutes (600000ms)
// This is shorter than the session expiry time to ensure tokens stay valid
const REFRESH_INTERVAL = 600000;
const refreshTokenPeriodically = async () => {
try {
// Skip time check if this is first load - we always refresh on first load
const isTimeToRefresh =
isFirstLoad.current ||
Date.now() - lastTokenRefresh > REFRESH_INTERVAL - 60000;
if (!isTimeToRefresh) {
return;
}
// Reset first load flag
if (isFirstLoad.current) {
isFirstLoad.current = false;
}
const response = await fetch("/api/auth/refresh", {
method: "POST",
credentials: "include",
});
if (response.ok) {
// Update last refresh time on success
setLastTokenRefresh(Date.now());
console.debug("Auth token refreshed successfully");
} else {
console.warn("Failed to refresh auth token:", response.status);
// If token refresh fails, try to get current user info
await onRefreshFail();
}
} catch (error) {
console.error("Error refreshing auth token:", error);
}
};
// Always attempt to refresh on first component mount
// This helps ensure tokens are fresh, especially after browser refresh
refreshTokenPeriodically();
// Set up interval for periodic refreshes
const intervalId = setInterval(refreshTokenPeriodically, REFRESH_INTERVAL);
// Also refresh token on window focus, but no more than once per minute
const handleVisibilityChange = () => {
if (
document.visibilityState === "visible" &&
Date.now() - lastTokenRefresh > 60000
) {
refreshTokenPeriodically();
}
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () => {
clearInterval(intervalId);
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, [user, lastTokenRefresh, onRefreshFail]);
return { lastTokenRefresh };
}