import { createAuth } from '@websanova/vue-auth'; import driverAuthBearer from '@websanova/vue-auth/dist/drivers/auth/bearer.esm.js'; import driverHttpAxios from '@websanova/vue-auth/dist/drivers/http/axios.1.x.esm.js'; import driverRouterVueRouter from '@websanova/vue-auth/dist/drivers/router/vue-router.2.x.esm.js'; import axios from 'axios'; import { createPinia } from 'pinia'; import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; import { AuthService } from './service/AuthService.js'; import { TokenRefreshManager } from './service/TokenRefreshManager.js'; import '@/assets/styles.scss'; import '@/assets/tailwind.css'; import BlockViewer from '@/components/BlockViewer.vue'; import { definePreset } from '@primevue/themes'; import Nora from '@primevue/themes/nora'; import { config } from 'md-editor-v3'; import PrimeVue from 'primevue/config'; import ConfirmationService from 'primevue/confirmationservice'; import ToastService from 'primevue/toastservice'; import { LoadingStore } from './stores/LoadingStore.js'; // Declare variables that will be used globally let authInstance = null; let tokenRefreshManager = null; config({ editorConfig: { renderDelay: 0, zIndex: 200000000 } }); var auth = createAuth({ plugins: { http: axios, router: router }, drivers: { http: driverHttpAxios, auth: driverAuthBearer, router: driverRouterVueRouter }, options: { notFoundRedirect: '/', authRedirect: '/', authRedirect: true, // niente redirect automatici notFoundRedirect: false, loginData: { url: '/api/auth/login', method: 'POST', redirect: '/home' }, logoutData: { url: '/api/auth/logout', redirect: '/auth/login' }, fetchData: { url: '/api/auth/fetch-user', method: 'GET', enabled: false }, refreshData: { url: '/api/auth/refresh-token', method: 'GET', enabled: true } } }); //axios.defaults.baseURL = import.meta.env.VITE_BACKEND_URL; axios.defaults.baseURL = 'http://localhost:8081'; console.log(import.meta.env.VITE_BACKEND_URL); const app = createApp(App); const pinia = createPinia(); const preset = definePreset(Nora, { semantic: { primary: { 50: '{violet.50}', 100: '{violet.100}', 200: '{violet.200}', 300: '{violet.300}', 400: '{violet.400}', 500: '{violet.500}', 600: '{violet.600}', 700: '{violet.700}', 800: '{violet.800}', 900: '{violet.900}', 950: '{violet.950}' }, colorScheme: { light: { surface: { 0: '#f3f3f3', 50: '{viva.50}', 100: '{viva.100}', 200: '{viva.200}', 300: '{viva.300}', 400: '{viva.400}', 500: '{viva.500}', 600: '{viva.600}', 700: '{viva.700}', 800: '{viva.800}', 900: '{viva.900}', 950: '{viva.950}' }, formField: { hoverBorderColor: '{primary.color}', borderColor: '{primary.color}' } }, dark: { surface: { 0: '#ffffff', 50: '{slate.50}', 100: '{slate.100}', 200: '{slate.200}', 300: '{slate.300}', 400: '{slate.400}', 500: '{slate.500}', 600: '{slate.600}', 700: '{slate.700}', 800: '{slate.800}', 900: '{slate.900}', 950: '{slate.950}' }, formField: { hoverBorderColor: '{primary.color}', borderColor: '{primary.color}' } } }, focusRing: { width: '2px', color: '{primary.color}', offset: '1px' } } }); app.use(pinia); app.use(router); app.use(PrimeVue, { theme: { preset: preset, options: { prefix: 'p', darkModeSelector: '.app-dark', cssLayer: false } } }); app.use(ToastService); app.use(ConfirmationService); app.use(auth); app.component('BlockViewer', BlockViewer); app.mount('#app'); // Store auth instance for interceptor and token refresh manager after app is mounted authInstance = app.config.globalProperties.$auth; tokenRefreshManager = new TokenRefreshManager(authInstance); // Start token refresh timer when user is authenticated if (authInstance.check()) { tokenRefreshManager.startRefreshTimer(); } // Listen for successful login to start token refresh timer window.addEventListener('auth-login-success', () => { console.log('[Main] Login success event received, starting token refresh timer'); if (tokenRefreshManager) { tokenRefreshManager.startRefreshTimer(); } }); // Stop token refresh timer on logout window.addEventListener('auth-logout', () => { console.log('[Main] Logout event received, stopping token refresh timer'); if (tokenRefreshManager) { tokenRefreshManager.stopRefreshTimer(); } }); const loadingStore = LoadingStore(); axios.interceptors.request.use( function (config) { loadingStore.another_loading = true; return config; }, function (error) { return Promise.reject(error); } ); axios.interceptors.response.use( function (response) { loadingStore.another_loading = false; return response; }, async function (error) { loadingStore.another_loading = false; // Don't handle auth-related URLs to prevent infinite loops const isAuthUrl = error.config && (error.config.url.includes('/api/auth/') || error.config.url.includes('/msauth/')); // Handle 403 errors by attempting token refresh (but not for auth URLs) if (error.response && error.response.status === 403 && !isAuthUrl) { console.log('[Interceptor] 403 error detected, attempting token refresh...'); // Check if we have an authenticated user and authInstance is available if (authInstance && authInstance.check && authInstance.check()) { try { // Use our custom AuthService to refresh tokens (both MSAL and classic) const refreshResult = await AuthService.refreshToken(authInstance); if (refreshResult.success && refreshResult.token) { console.log('[Interceptor] Token refresh successful, updating auth and retrying request...'); // Update the auth token authInstance.token(null, refreshResult.token, false); // Update the original request with new token error.config.headers['Authorization'] = `Bearer ${refreshResult.token}`; // Retry the original request return axios.request(error.config); } else { console.error('[Interceptor] Token refresh failed:', refreshResult.error); throw new Error(refreshResult.error); } } catch (refreshError) { console.error('[Interceptor] Token refresh process failed:', refreshError); // If refresh fails, logout and redirect to login try { // Stop token refresh timer window.dispatchEvent(new CustomEvent('auth-logout')); await AuthService.logout(); if (authInstance && authInstance.logout) { authInstance.logout({ redirect: '/auth/login' }); } else { window.location.href = '/auth/login'; } } catch (logoutError) { console.error('[Interceptor] Logout failed:', logoutError); // Force redirect to login window.location.href = '/auth/login'; } return Promise.reject(refreshError); } } else { console.log('[Interceptor] No authenticated user for non-auth 403, ignoring...'); } } return Promise.reject(error); } );