interface User { id: string email: string username: string name: string authMethod: string } interface AuthState { user: User | null authenticated: boolean } export const useCustomAuth = () => { const user = ref(null) const authenticated = ref(false) const loading = ref(true) const refreshing = ref(false) // Check authentication status const checkAuth = async () => { try { loading.value = true const data = await $fetch('/api/auth/session') user.value = data.user authenticated.value = data.authenticated console.log('[CUSTOM_AUTH] Session check result:', { authenticated: data.authenticated, userId: data.user?.id }) } catch (error) { console.error('[CUSTOM_AUTH] Session check failed:', error) user.value = null authenticated.value = false } finally { loading.value = false } } // Refresh token const refreshToken = async () => { if (refreshing.value) return false try { refreshing.value = true console.log('[CUSTOM_AUTH] Attempting token refresh...') const response = await $fetch<{ success: boolean }>('/api/auth/refresh', { method: 'POST' }) if (response.success) { console.log('[CUSTOM_AUTH] Token refresh successful') await checkAuth() // Re-check auth state after refresh return true } return false } catch (error) { console.error('[CUSTOM_AUTH] Token refresh failed:', error) // Clear auth state on refresh failure user.value = null authenticated.value = false return false } finally { refreshing.value = false } } // Login with Keycloak const login = () => { const authUrl = 'https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/auth?' + new URLSearchParams({ client_id: 'client-portal', redirect_uri: 'https://client.portnimara.dev/api/auth/keycloak/callback', response_type: 'code', scope: 'openid profile email', state: Math.random().toString(36).substring(2) }).toString() console.log('[CUSTOM_AUTH] Redirecting to Keycloak login:', authUrl) navigateTo(authUrl, { external: true }) } // Logout const logout = async () => { try { console.log('[CUSTOM_AUTH] Initiating logout...') // Clear local state immediately user.value = null authenticated.value = false // Redirect to logout endpoint await navigateTo('/api/auth/logout', { external: true }) } catch (error) { console.error('[CUSTOM_AUTH] Logout failed:', error) // Fallback: redirect to login await navigateTo('/login') } } // Initialize auth state on composable creation onMounted(() => { checkAuth() }) return { user: readonly(user), authenticated: readonly(authenticated), loading: readonly(loading), refreshing: readonly(refreshing), login, logout, checkAuth, refreshToken } }