accounts/dashboard-fresh/lib/auth/use_auth.ts
Haitao Pan b3bdbc1a80 feat(auth): implement token authentication system across services
- Add token service and MFA service to account service
- Implement auth middleware for request validation
- Add token-based auth to dashboard and RAG server
- Update configuration files for auth settings
2025-11-05 19:28:23 +08:00

131 lines
3.0 KiB
TypeScript

// React hook for authentication
import { useState, useEffect, useCallback } from 'preact/hooks';
import { tokenService, TokenPair, authFetch } from './token_service.ts';
export interface User {
user_id: string;
email: string;
roles: string[];
}
export function useAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
// Load tokens and user info on mount
useEffect(() => {
tokenService.loadTokens();
loadUserInfo();
}, []);
/**
* Load user information from access token
*/
const loadUserInfo = useCallback(async () => {
try {
setLoading(true);
const accessToken = tokenService.getAccessToken();
if (!accessToken) {
setUser(null);
setLoading(false);
return;
}
// Decode token to get user info
const claims = tokenService.decodeToken(accessToken);
setUser({
user_id: claims.user_id,
email: claims.email,
roles: claims.roles,
});
setError(null);
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load user info');
setUser(null);
tokenService.clearTokens();
} finally {
setLoading(false);
}
}, []);
/**
* Login with credentials
*/
const login = useCallback(async (email: string, password: string): Promise<boolean> => {
try {
setLoading(true);
setError(null);
const response = await authFetch('/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
throw new Error('Login failed');
}
const data: TokenPair = await response.json();
tokenService.setTokens(data);
await loadUserInfo();
return true;
} catch (err) {
setError(err instanceof Error ? err.message : 'Login failed');
return false;
} finally {
setLoading(false);
}
}, [loadUserInfo]);
/**
* Logout
*/
const logout = useCallback(() => {
tokenService.clearTokens();
setUser(null);
setError(null);
}, []);
/**
* Refresh access token
*/
const refreshToken = useCallback(async (): Promise<boolean> => {
try {
const newToken = await tokenService.refreshAccessToken();
if (newToken) {
await loadUserInfo();
return true;
}
return false;
} catch (err) {
setError(err instanceof Error ? err.message : 'Token refresh failed');
logout();
return false;
}
}, [loadUserInfo, logout]);
/**
* Check if user has specific role
*/
const hasRole = useCallback((role: string): boolean => {
return user?.roles.includes(role) ?? false;
}, [user]);
return {
user,
loading,
error,
login,
logout,
refreshToken,
hasRole,
isAuthenticated: user !== null,
};
}