Files
foxhunt/web-dashboard/src/hooks/useAuth.ts
jgrusewski 84877e5146 feat: add auth gRPC service + migrate dashboard from REST/WS to grpc-web
Backend (Rust):
- Create proto/auth.proto with Login and RefreshToken RPCs
- Implement AuthGrpcService in services/api with JWT issuance
- Register as unauthenticated service in main.rs (pre-auth)
- Update JWT issuer from foxhunt-api-gateway to foxhunt-api

Dashboard (TypeScript):
- Install @connectrpc/connect-web + @bufbuild/protobuf
- Generate TypeScript proto clients via buf (src/gen/)
- Create grpc.ts transport with JWT interceptor
- Rewrite all useApi hooks to typed gRPC calls
- Replace WebSocket with useGrpcStream server-streaming hooks
- Migrate all 6 pages + 6 components to grpc-web
- Delete api.ts, websocket.ts, useWebSocket.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 00:05:18 +01:00

43 lines
1007 B
TypeScript

import { useCallback, useSyncExternalStore } from "react";
import {
clearTokens,
getToken,
isAuthenticated,
setTokens,
} from "../lib/auth";
/** Simple external store for auth state reactivity */
const authListeners: Set<() => void> = new Set();
function notifyAuthChange() {
authListeners.forEach((l) => l());
}
function subscribeAuth(listener: () => void) {
authListeners.add(listener);
return () => {
authListeners.delete(listener);
};
}
/** React hook for authentication state and actions */
export function useAuth() {
const authenticated = useSyncExternalStore(subscribeAuth, isAuthenticated);
const token = useSyncExternalStore(subscribeAuth, getToken);
const login = useCallback(
(accessToken: string, refreshToken?: string) => {
setTokens(accessToken, refreshToken);
notifyAuthChange();
},
[],
);
const logout = useCallback(() => {
clearTokens();
notifyAuthChange();
}, []);
return { authenticated, token, login, logout };
}