import { TokenManager } from '@sentryagent/idp-sdk'; const SESSION_KEY = 'agentidp_credentials'; interface StoredCredentials { clientId: string; clientSecret: string; baseUrl: string; } /** * Persists user credentials to sessionStorage (cleared on tab close). */ export function saveCredentials(creds: StoredCredentials): void { sessionStorage.setItem(SESSION_KEY, JSON.stringify(creds)); } /** * Retrieves credentials from sessionStorage. * Returns null if not logged in. */ export function loadCredentials(): StoredCredentials | null { const raw = sessionStorage.getItem(SESSION_KEY); if (!raw) return null; try { return JSON.parse(raw) as StoredCredentials; } catch { return null; } } /** * Removes credentials from sessionStorage (logout). */ export function clearCredentials(): void { sessionStorage.removeItem(SESSION_KEY); } /** * Returns true if the user has stored credentials. */ export function isAuthenticated(): boolean { return loadCredentials() !== null; } /** * Validates stored credentials by requesting a token. * Returns true if successful; false on auth failure. */ export async function validateCredentials(creds: StoredCredentials): Promise { try { const tm = new TokenManager(creds.baseUrl, creds.clientId, creds.clientSecret, 'agents:read agents:write tokens:read audit:read'); await tm.getToken(); return true; } catch { return false; } } // ── React context ────────────────────────────────────────────────────────────── import * as React from 'react'; import { useNavigate } from 'react-router-dom'; interface AuthContextValue { credentials: StoredCredentials | null; login: (creds: StoredCredentials) => Promise; logout: () => void; } const AuthContext = React.createContext(null); /** * Provides authentication state to the application. * Reads initial state from sessionStorage on mount. */ export function AuthProvider({ children }: { children: React.ReactNode }): React.JSX.Element { const [credentials, setCredentials] = React.useState(loadCredentials); const navigate = useNavigate(); const login = React.useCallback(async (creds: StoredCredentials): Promise => { const valid = await validateCredentials(creds); if (valid) { saveCredentials(creds); setCredentials(creds); } return valid; }, []); const logout = React.useCallback((): void => { clearCredentials(); setCredentials(null); navigate('/dashboard/login'); }, [navigate]); const value = React.useMemo(() => ({ credentials, login, logout }), [credentials, login, logout]); return {children}; } /** * Returns the current authentication context. * Must be used inside . */ export function useAuth(): AuthContextValue { const ctx = React.useContext(AuthContext); if (!ctx) throw new Error('useAuth must be used within AuthProvider'); return ctx; }