Files
cameleer-server/ui/src/auth/use-auth.ts
hsiegeln 27f2503640
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m27s
CI / docker (push) Successful in 1m13s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 42s
fix: clean up runtime UI and harden session expiry handling
Remove redundant "X/X LIVE" badge from runtime page, breadcrumb trail
and routes section from agent detail page (pills moved into Process
Information card). Fix session expiry: guard against concurrent 401
refresh races and skip re-entrant triggers on auth endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 22:33:44 +02:00

49 lines
1.4 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { useAuthStore } from './auth-store';
import { configureAuth } from '../api/client';
import { useNavigate } from 'react-router';
export function useAuth() {
const { accessToken, isAuthenticated, refresh, logout } = useAuthStore();
const navigate = useNavigate();
const refreshingRef = useRef(false);
useEffect(() => {
configureAuth({
onUnauthorized: async () => {
if (refreshingRef.current) return;
refreshingRef.current = true;
try {
const ok = await useAuthStore.getState().refresh();
if (!ok) {
useAuthStore.getState().logout();
navigate('/login', { replace: true });
}
} finally {
refreshingRef.current = false;
}
},
});
}, [navigate]);
useEffect(() => {
if (!isAuthenticated) return;
const interval = setInterval(async () => {
const token = useAuthStore.getState().accessToken;
if (!token) return;
try {
const payload = JSON.parse(atob(token.split('.')[1]));
const expiresIn = payload.exp * 1000 - Date.now();
if (expiresIn < 5 * 60 * 1000) {
await refresh();
}
} catch {
// Token parse failure
}
}, 30_000);
return () => clearInterval(interval);
}, [isAuthenticated, refresh]);
return { accessToken, isAuthenticated, logout };
}