fix(auth): Address high and medium priority security and build findings

This commit is contained in:
Yunxiao Xu
2026-02-18 14:50:09 -08:00
parent 6131f27142
commit f5aeb9d956
5 changed files with 32 additions and 12 deletions

View File

@@ -6,7 +6,7 @@ import { AuthService } from '@/services/auth'
* It proactively refreshes the session to prevent expiration while the user is active.
*/
export function useSilentRefresh(isAuthenticated: boolean) {
const timerRef = useRef<NodeJS.Timeout | null>(null)
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)
const refresh = useCallback(async () => {
try {

View File

@@ -4,7 +4,6 @@ import './index.css'
import App from './App.tsx'
import { TooltipProvider } from "@/components/ui/tooltip"
import { BrowserRouter } from "react-router-dom"
import { ThemeProvider } from "./components/theme-provider"
createRoot(document.getElementById('root')!).render(
<StrictMode>

View File

@@ -17,14 +17,23 @@ export const registerUnauthorizedCallback = (callback: () => void) => {
// State to manage multiple concurrent refreshes
let isRefreshing = false
let refreshSubscribers: ((token: string) => void)[] = []
let refreshErrorSubscribers: ((error: any) => void)[] = []
const subscribeTokenRefresh = (callback: (token: string) => void) => {
refreshSubscribers.push(callback)
const subscribeTokenRefresh = (onSuccess: (token: string) => void, onError: (error: any) => void) => {
refreshSubscribers.push(onSuccess)
refreshErrorSubscribers.push(onError)
}
const onRefreshed = (token: string) => {
refreshSubscribers.forEach((callback) => callback(token))
refreshSubscribers = []
refreshErrorSubscribers = []
}
const onRefreshFailed = (error: any) => {
refreshErrorSubscribers.forEach((callback) => callback(error))
refreshSubscribers = []
refreshErrorSubscribers = []
}
// Add a response interceptor to handle 401s
@@ -41,11 +50,11 @@ api.interceptors.response.use(
if (error.response?.status === 401 && !isAuthEndpoint && !isRefreshEndpoint && !originalRequest._retry) {
if (isRefreshing) {
// Wait for the current refresh to complete
return new Promise((resolve) => {
subscribeTokenRefresh((token) => {
// Re-run the original request
resolve(api(originalRequest))
})
return new Promise((resolve, reject) => {
subscribeTokenRefresh(
(_token) => resolve(api(originalRequest)),
(err) => reject(err)
)
})
}
@@ -65,7 +74,7 @@ api.interceptors.response.use(
return api(originalRequest)
} catch (refreshError) {
isRefreshing = false
refreshSubscribers = []
onRefreshFailed(refreshError)
console.error("Reactive refresh failed:", refreshError)
// Final failure - session is dead