From f5a5793309d9d479e77bee105b74ae67f22333da Mon Sep 17 00:00:00 2001 From: ValueOn AG Date: Fri, 8 May 2026 11:49:24 +0200 Subject: [PATCH] dns switch poweron-center to poweron.swiss --- .github/workflows/poweron_nyla_int.yml | 2 +- .github/workflows/poweron_nyla_main.yml | 2 +- .gitignore | 6 +- README.md | 31 ++-- config/.env.dev | 34 ----- config/.env.int | 33 ---- config/.env.prod | 33 ---- config/env-poweron-nyla-dev.env | 6 + config/env-poweron-nyla-int.env | 6 + config/env-poweron-nyla-prod.env | 6 + env.d.ts | 15 +- package-lock.json | 36 ----- package.json | 2 - src/App.tsx | 3 - src/hooks/useAuthentication.ts | 193 +++--------------------- src/hooks/useUsers.ts | 32 +--- src/pages/Register.tsx | 4 +- src/providers/auth/AuthProvider.tsx | 99 ------------ src/providers/auth/ProtectedRoute.tsx | 89 +---------- src/providers/auth/authConfig.ts | 45 ------ 20 files changed, 68 insertions(+), 609 deletions(-) delete mode 100644 config/.env.dev delete mode 100644 config/.env.int delete mode 100644 config/.env.prod create mode 100644 config/env-poweron-nyla-dev.env create mode 100644 config/env-poweron-nyla-int.env create mode 100644 config/env-poweron-nyla-prod.env delete mode 100644 src/providers/auth/AuthProvider.tsx delete mode 100644 src/providers/auth/authConfig.ts diff --git a/.github/workflows/poweron_nyla_int.yml b/.github/workflows/poweron_nyla_int.yml index c315780..7998da8 100644 --- a/.github/workflows/poweron_nyla_int.yml +++ b/.github/workflows/poweron_nyla_int.yml @@ -27,7 +27,7 @@ jobs: - name: Copy integration environment file run: | - cp config/.env.int .env + cp config/env-poweron-nyla-int.env .env - name: Install dependencies run: | diff --git a/.github/workflows/poweron_nyla_main.yml b/.github/workflows/poweron_nyla_main.yml index 50877ea..1e0c31e 100644 --- a/.github/workflows/poweron_nyla_main.yml +++ b/.github/workflows/poweron_nyla_main.yml @@ -27,7 +27,7 @@ jobs: - name: Copy production environment file run: | - cp config/.env.prod .env + cp config/env-poweron-nyla-prod.env .env - name: Install dependencies run: | diff --git a/.gitignore b/.gitignore index f0524e8..b7aac00 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,5 @@ dist-ssr .cursorignore -# Keep environment template files in config/ -!config/.env.dev -!config/.env.int -!config/.env.prod \ No newline at end of file +# Keep environment files in config/ (naming: env-.env) +!config/env-*.env \ No newline at end of file diff --git a/README.md b/README.md index 97574fe..f792e3a 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ ```mermaid graph TB %% Environment Files - ENV_DEV[".env.dev
Development"] - ENV_PROD[".env.prod
Production"] - ENV_INT[".env.int
Integration"] + ENV_DEV["env-poweron-nyla-dev.env
Development"] + ENV_PROD["env-poweron-nyla-prod.env
Production"] + ENV_INT["env-poweron-nyla-int.env
Integration"] %% Configuration System CONFIG_TS["config.ts
TypeScript Config
(React Frontend)"] @@ -114,30 +114,25 @@ The app uses a **dual configuration system** to handle environment variables acr - **Used by:** Express servers and build scripts ### Environment Files -- **`config/.env.dev`** - Development environment variables - - **Why:** Separate config for local development with debug settings - - **How:** Copied to root `.env` by `npm run dev` command - - **Contains:** Local API URLs, debug flags, dev-specific settings -- **`config/.env.prod`** - Production environment variables - - **Why:** Production-specific settings (live API URLs, optimized settings) - - **How:** Copied to root `.env` by GitHub Actions workflow - - **Contains:** Production API URLs, security settings, performance configs +Naming convention: `env-.env` — matches the GitHub Actions workflow that uses it. -- **`config/.env.int`** - Integration environment variables - - **Why:** Testing environment that mirrors production but with test data - - **How:** Copied to root `.env` by integration deployment workflow - - **Contains:** Staging API URLs, test user credentials, integration settings +- **`config/env-poweron-nyla-dev.env`** — Local development (localhost gateway) +- **`config/env-poweron-nyla-int.env`** — Integration (used by `poweron_nyla_int` workflow) +- **`config/env-poweron-nyla-prod.env`** — Production (used by `poweron_nyla_main` workflow) + +Each env is copied to root `.env` at build time (by CI or manually for local dev). ### Usage ```bash -# Development (loads .env.dev) +# Local development — copy env then start Vite +cp config/env-poweron-nyla-dev.env .env npm run dev -# Production build (loads .env.prod) +# Production build (CI copies env-poweron-nyla-prod.env → .env) npm run build:prod -# Integration build (loads .env.int) +# Integration build (CI copies env-poweron-nyla-int.env → .env) npm run build:int ``` diff --git a/config/.env.dev b/config/.env.dev deleted file mode 100644 index 89a972a..0000000 --- a/config/.env.dev +++ /dev/null @@ -1,34 +0,0 @@ -# Development Environment Configuration -# Frontend Nyla - Development - -# API Configuration -VITE_API_BASE_URL="http://localhost:8000/" -VITE_API_TIMEOUT=10000 - -# Microsoft Entra ID Configuration -VITE_MICROSOFT_CLIENT_ID=24cd6c8a-b592-4905-a5ba-d5fa9f911154 -VITE_MICROSOFT_TENANT_ID=6a51aaeb-2467-4186-9504-2a05aedc591f -VITE_ENTRA_CLIENT_SECRET=2iw8Q~jwqG1iacxHopBt5pstu6R45UC1gIQabcbD -VITE_ENTRA_AUTHORITY=https://login.microsoftonline.com/6a51aaeb-2467-4186-9504-2a05aedc591f -VITE_ENTRA_REDIRECT_PATH=/auth/callback/ -VITE_ENTRA_REDIRECT_URI=http://localhost:8000/api/msft/auth/callback/ - -# Application Configuration -VITE_APP_NAME=PowerOn Nyla dev -VITE_APP_VERSION=0.0.0 -VITE_APP_ENVIRONMENT=development - -# Debug Configuration -VITE_DEBUG=true -VITE_LOG_LEVEL=debug -VITE_ENABLE_CONSOLE_LOGS=true - -# Feature Flags -VITE_ENABLE_ANALYTICS=false -VITE_ENABLE_ERROR_REPORTING=false -VITE_ENABLE_PERFORMANCE_MONITORING=false - -# Development Server -VITE_DEV_SERVER_PORT=5176 -VITE_DEV_SERVER_HOST=localhost -VITE_DEV_SERVER_HTTPS=false \ No newline at end of file diff --git a/config/.env.int b/config/.env.int deleted file mode 100644 index 32874bc..0000000 --- a/config/.env.int +++ /dev/null @@ -1,33 +0,0 @@ -# Integration/Test Environment Configuration -# Frontend Nyla - Integration - -# API Configuration -VITE_API_BASE_URL=https://gateway-int.poweron-center.net -VITE_API_TIMEOUT=12000 - -# Microsoft Entra ID Configuration -VITE_MICROSOFT_CLIENT_ID=24cd6c8a-b592-4905-a5ba-d5fa9f911154 -VITE_MICROSOFT_TENANT_ID=6a51aaeb-2467-4186-9504-2a05aedc591f -VITE_ENTRA_CLIENT_SECRET=2iw8Q~jwqG1iacxHopBt5pstu6R45UC1gIQabcbD -VITE_ENTRA_AUTHORITY=https://login.microsoftonline.com/6a51aaeb-2467-4186-9504-2a05aedc591f -VITE_ENTRA_REDIRECT_PATH=/auth/callback/ -VITE_ENTRA_REDIRECT_URI=https://gateway-int.poweron-center.net/api/msft/auth/callback/ - -# Application Configuration -VITE_APP_NAME=Poweron Nyla int -VITE_APP_VERSION=0.0.0 -VITE_APP_ENVIRONMENT=integration - -# Debug Configuration -VITE_DEBUG=true -VITE_LOG_LEVEL=info -VITE_ENABLE_CONSOLE_LOGS=true - -# Feature Flags -VITE_ENABLE_ANALYTICS=true -VITE_ENABLE_ERROR_REPORTING=true -VITE_ENABLE_PERFORMANCE_MONITORING=true - -# Test Configuration -VITE_ENABLE_MOCK_DATA=false -VITE_ENABLE_TEST_MODE=true diff --git a/config/.env.prod b/config/.env.prod deleted file mode 100644 index 0db5112..0000000 --- a/config/.env.prod +++ /dev/null @@ -1,33 +0,0 @@ -# Production Environment Configuration -# Frontend Nyla - Production - -# API Configuration -VITE_API_BASE_URL=https://gateway-prod.poweron-center.net -VITE_API_TIMEOUT=15000 - -# Microsoft Entra ID Configuration -VITE_MICROSOFT_CLIENT_ID=24cd6c8a-b592-4905-a5ba-d5fa9f911154 -VITE_MICROSOFT_TENANT_ID=6a51aaeb-2467-4186-9504-2a05aedc591f -VITE_ENTRA_CLIENT_SECRET=2iw8Q~jwqG1iacxHopBt5pstu6R45UC1gIQabcbD -VITE_ENTRA_AUTHORITY=https://login.microsoftonline.com/6a51aaeb-2467-4186-9504-2a05aedc591f -VITE_ENTRA_REDIRECT_PATH=/auth/callback/ -VITE_ENTRA_REDIRECT_URI=https://gateway-prod.poweron-center.net/api/msft/auth/callback/ - -# Application Configuration -VITE_APP_NAME=PowerOn Nyla -VITE_APP_VERSION=0.0.0 -VITE_APP_ENVIRONMENT=production - -# Debug Configuration -VITE_DEBUG=false -VITE_LOG_LEVEL=error -VITE_ENABLE_CONSOLE_LOGS=false - -# Feature Flags -VITE_ENABLE_ANALYTICS=true -VITE_ENABLE_ERROR_REPORTING=true -VITE_ENABLE_PERFORMANCE_MONITORING=true - -# Security Configuration -VITE_ENABLE_HTTPS=true -VITE_ENABLE_CSP=true diff --git a/config/env-poweron-nyla-dev.env b/config/env-poweron-nyla-dev.env new file mode 100644 index 0000000..a66d513 --- /dev/null +++ b/config/env-poweron-nyla-dev.env @@ -0,0 +1,6 @@ +# Environment: poweron-nyla-dev (local development) +# Consumed by: Vite build (title) + SPA runtime (getApiBaseUrl / getAppName) +# Auth and secrets live on the gateway — never in frontend env. + +VITE_API_BASE_URL="http://localhost:8000/" +VITE_APP_NAME=PowerOn Nyla dev diff --git a/config/env-poweron-nyla-int.env b/config/env-poweron-nyla-int.env new file mode 100644 index 0000000..6655d68 --- /dev/null +++ b/config/env-poweron-nyla-int.env @@ -0,0 +1,6 @@ +# Environment: poweron-nyla-int (integration) +# Consumed by: Vite build (title) + SPA runtime (getApiBaseUrl / getAppName) +# Auth and secrets live on the gateway — never in frontend env. + +VITE_API_BASE_URL=https://gateway-int.poweron.swiss +VITE_APP_NAME=Poweron Nyla int diff --git a/config/env-poweron-nyla-prod.env b/config/env-poweron-nyla-prod.env new file mode 100644 index 0000000..7c3adff --- /dev/null +++ b/config/env-poweron-nyla-prod.env @@ -0,0 +1,6 @@ +# Environment: poweron-nyla-prod (production) +# Consumed by: Vite build (title) + SPA runtime (getApiBaseUrl / getAppName) +# Auth and secrets live on the gateway — never in frontend env. + +VITE_API_BASE_URL=https://gateway-prod.poweron.swiss +VITE_APP_NAME=PowerOn Nyla diff --git a/env.d.ts b/env.d.ts index 633661e..0533123 100644 --- a/env.d.ts +++ b/env.d.ts @@ -1,15 +1,6 @@ /// interface ImportMetaEnv { - readonly VITE_API_URL: string - readonly VITE_MICROSOFT_CLIENT_ID: string - readonly VITE_MICROSOFT_TENANT_ID: string - readonly VITE_ENTRA_CLIENT_SECRET: string - readonly VITE_ENTRA_AUTHORITY: string - readonly VITE_ENTRA_REDIRECT_PATH: string - readonly VITE_ENTRA_REDIRECT_URI: string - } - -interface ImportMeta { - readonly env: ImportMetaEnv - } \ No newline at end of file + readonly VITE_API_BASE_URL?: string + readonly VITE_APP_NAME?: string +} diff --git a/package-lock.json b/package-lock.json index 60224ca..d1fd27b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,8 +8,6 @@ "name": "frontend_nyla_new", "version": "0.0.0", "dependencies": { - "@azure/msal-browser": "^4.12.0", - "@azure/msal-react": "^3.0.12", "@monaco-editor/react": "^4.7.0", "@types/leaflet": "^1.9.21", "@xstate/react": "^5.0.0", @@ -101,40 +99,6 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, - "node_modules/@azure/msal-browser": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.16.0.tgz", - "integrity": "sha512-yF8gqyq7tVnYftnrWaNaxWpqhGQXoXpDfwBtL7UCGlIbDMQ1PUJF/T2xCL6NyDNHoO70qp1xU8GjjYTyNIefkw==", - "license": "MIT", - "dependencies": { - "@azure/msal-common": "15.9.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-common": { - "version": "15.9.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.9.0.tgz", - "integrity": "sha512-lbz/D+C9ixUG3hiZzBLjU79a0+5ZXCorjel3mwXluisKNH0/rOS/ajm8yi4yI9RP5Uc70CAcs9Ipd0051Oh/kA==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-react": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/@azure/msal-react/-/msal-react-3.0.16.tgz", - "integrity": "sha512-fIFc3z9UrHoOCG4rApNWMRr83DnQlo+CHfLSPNBQa4rndIkr+XYBpdYDqlzqtmikRf3A+CYNVOQ+lQX6jM0zdw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@azure/msal-browser": "^4.16.0", - "react": "^16.8.0 || ^17 || ^18 || ^19" - } - }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", diff --git a/package.json b/package.json index 2145710..cd3e78e 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,6 @@ "test:coverage": "vitest run --coverage" }, "dependencies": { - "@azure/msal-browser": "^4.12.0", - "@azure/msal-react": "^3.0.12", "@monaco-editor/react": "^4.7.0", "@types/leaflet": "^1.9.21", "@xstate/react": "^5.0.0", diff --git a/src/App.tsx b/src/App.tsx index c81e8fb..499bb37 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -25,7 +25,6 @@ import Reset from './pages/Reset'; import { InvitePage } from './pages/InvitePage'; // Providers -import { AuthProvider } from './providers/auth/AuthProvider'; import { ProtectedRoute } from './providers/auth/ProtectedRoute'; import { LanguageProvider } from './providers/language/LanguageContext'; import { ToastProvider } from './contexts/ToastContext'; @@ -71,7 +70,6 @@ function App() { return ( - @@ -240,7 +238,6 @@ function App() { - ); } diff --git a/src/hooks/useAuthentication.ts b/src/hooks/useAuthentication.ts index a67bcac..fb901ba 100644 --- a/src/hooks/useAuthentication.ts +++ b/src/hooks/useAuthentication.ts @@ -1,15 +1,12 @@ import { useState } from 'react'; -import { useMsal } from '@azure/msal-react'; import api from '../api'; -import { useApiRequest } from './useApi'; import { getApiBaseUrl } from '../../config/config'; import { setUserDataCache, clearUserDataCache, type CachedUserData } from '../utils/userCache'; import { loginApi, fetchCurrentUserApi, registerApi, - registerWithMsalApi, checkUsernameAvailabilityApi, logoutApi, requestPasswordResetApi, @@ -18,7 +15,6 @@ import { type RegisterResponse, type UsernameAvailabilityResponse, type RegisterData, - type MsalRegisterData, type PasswordResetRequestResponse, type PasswordResetResponse } from '../api/authApi'; @@ -408,48 +404,6 @@ export function useGoogleAuth() { }; } -// Microsoft Registration -export function useMsalRegister() { - const { instance, accounts } = useMsal(); - const { request, isLoading, error } = useApiRequest(); - - const registerWithMsal = async (): Promise => { - try { - if (!accounts || accounts.length === 0) { - // If not signed in with Microsoft, sign in first - await instance.loginPopup({ - scopes: ['user.read'] - }); - } - - // Get the current account - const currentAccount = instance.getAllAccounts()[0]; - if (!currentAccount) { - throw new Error('No Microsoft account found'); - } - - // Prepare user data from Microsoft account - const userData: MsalRegisterData = { - username: currentAccount.username, - email: currentAccount.username, - fullName: currentAccount.name || currentAccount.username, - language: 'de' - }; - - // Register the user through our backend - return await registerWithMsalApi(request, userData); - } catch (error: any) { - throw error; - } - }; - - return { - registerWithMsal, - error, - isLoading - }; -} - // Username availability check export function useUsernameAvailability() { const [isChecking, setIsChecking] = useState(false); @@ -568,145 +522,32 @@ export function useLogout() { const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); + const _clearLocalState = () => { + clearUserDataCache(); + localStorage.removeItem('authToken'); + sessionStorage.clear(); + document.cookie.split(";").forEach((c) => { + const name = c.split("=")[0].trim(); + if (name) { + document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; + } + }); + }; + const logout = async (): Promise => { setIsLoading(true); setError(null); try { - // Call logout endpoint to clear JWT tokens on server await logoutApi(); - - - - // CRITICAL: Wait for browser to process Set-Cookie headers from logout response - // This gives the browser time to clear httpOnly cookies before redirect + // Give browser time to process Set-Cookie headers from logout response await new Promise(resolve => setTimeout(resolve, 1000)); - - // Clear user data cache from sessionStorage - clearUserDataCache(); - - // Clear auth authority from sessionStorage - sessionStorage.removeItem('auth_authority'); - - // Clear MSAL cache tokens from localStorage - // MSAL stores tokens with keys starting with 'msal.' - const keysToRemove = []; - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - if (key && ( - key.startsWith('msal.') || - key === 'auth_token' || - key === 'refresh_token' || - key.includes('token') || - key.includes('auth') || - key.includes('msal') - )) { - keysToRemove.push(key); - } - } - keysToRemove.forEach(key => { - - localStorage.removeItem(key); - }); - - // Clear ALL MSAL cache data (including account keys, token keys, version) - const msalKeysToRemove = []; - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - if (key && key.startsWith('msal.')) { - msalKeysToRemove.push(key); - } - } - msalKeysToRemove.forEach(key => { - - localStorage.removeItem(key); - }); - - // Clear sessionStorage as well (CSRF tokens, etc.) - sessionStorage.clear(); - - // Clear cookies as backup (in case backend doesn't clear them properly) - // Note: This only works for cookies that are accessible to JavaScript - - - const cookies = document.cookie.split(";"); - - - cookies.forEach(function(c) { - const cookieName = c.split("=")[0].trim(); - - - if (cookieName === 'auth_token' || cookieName === 'refresh_token' || cookieName.includes('token') || cookieName.includes('msal')) { - - document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; - } - }); - - - - // Redirect to login page - window.location.href = '/login?logout=true'; - } catch (error: any) { - let errorMessage = 'Logout failed'; - - if (error.response) { - errorMessage = error.response.data?.detail || errorMessage; - } - - setError(errorMessage); - - // Even if logout fails on server, clear local data and redirect - clearUserDataCache(); - sessionStorage.removeItem('auth_authority'); - - // Clear MSAL cache tokens from localStorage - const keysToRemove = []; - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - if (key && ( - key.startsWith('msal.') || - key === 'auth_token' || - key === 'refresh_token' || - key.includes('token') || - key.includes('auth') || - key.includes('msal') - )) { - keysToRemove.push(key); - } - } - keysToRemove.forEach(key => { - - localStorage.removeItem(key); - }); - - // Clear ALL MSAL cache data (including account keys, token keys, version) - const msalKeysToRemove = []; - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - if (key && key.startsWith('msal.')) { - msalKeysToRemove.push(key); - } - } - msalKeysToRemove.forEach(key => { - - localStorage.removeItem(key); - }); - - // Clear sessionStorage as well - sessionStorage.clear(); - - // Clear cookies as backup (in case backend doesn't clear them properly) - document.cookie.split(";").forEach(function(c) { - const cookieName = c.split("=")[0].trim(); - if (cookieName === 'auth_token' || cookieName === 'refresh_token' || cookieName.includes('token') || cookieName.includes('msal')) { - - document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; - } - }); - - window.location.href = '/login?logout=true'; + } catch (err: any) { + setError(err.response?.data?.detail || 'Logout failed'); } finally { + _clearLocalState(); setIsLoading(false); + window.location.href = '/login?logout=true'; } }; diff --git a/src/hooks/useUsers.ts b/src/hooks/useUsers.ts index acd7242..7c1c1e4 100644 --- a/src/hooks/useUsers.ts +++ b/src/hooks/useUsers.ts @@ -172,36 +172,14 @@ export function useCurrentUser() { // Clear auth authority from sessionStorage sessionStorage.removeItem('auth_authority'); - // Optional: clear MSAL browser cache only (PowerOn JWT lives in httpOnly cookies + backend). - // Do not call msal.logoutRedirect — that signs the user out of Microsoft globally. - for (let i = localStorage.length - 1; i >= 0; i--) { - const key = localStorage.key(i); - if (key && key.startsWith('msal.')) { - localStorage.removeItem(key); - } - } + localStorage.removeItem('authToken'); - // Clear cookies as backup (in case backend doesn't clear them properly) - // Note: This only works for cookies that are accessible to JavaScript - console.log('🍪 Checking cookies for cleanup...'); - console.log('🍪 All cookies:', document.cookie); - - const cookies = document.cookie.split(";"); - console.log('🍪 Cookie count:', cookies.length); - - cookies.forEach(function(c) { - const cookieName = c.split("=")[0].trim(); - console.log('🍪 Checking cookie:', cookieName); - - if (cookieName === 'auth_token' || cookieName === 'refresh_token' || cookieName.includes('token') || cookieName.includes('msal')) { - console.log('🗑️ Clearing cookie:', cookieName); - document.cookie = cookieName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; + document.cookie.split(";").forEach((c) => { + const name = c.split("=")[0].trim(); + if (name) { + document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; } }); - - console.log('🍪 Cookies after cleanup attempt:', document.cookie); - - console.log('✅ Cleanup completed'); // Redirect to login or home page console.log('🔄 Redirecting to login page...'); diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index 05b4a3b..575665f 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -3,7 +3,7 @@ import { useNavigate, useLocation } from 'react-router-dom'; import { FaEnvelopeOpenText } from 'react-icons/fa'; import styles from './Register.module.css'; -import { useRegister, useMsalRegister, useUsernameAvailability } from '../hooks/useAuthentication'; +import { useRegister, useUsernameAvailability } from '../hooks/useAuthentication'; import { generateAndStoreCSRFToken } from '../utils/csrfUtils'; import { PENDING_INVITATION_KEY } from './InvitePage'; import { LanguageSelector } from '../components/UiComponents/LanguageSelector'; @@ -21,7 +21,6 @@ function Register() { const navigate = useNavigate(); const location = useLocation(); const { register, error: registerError, isLoading } = useRegister(); - const { error: msalError } = useMsalRegister(); const { checkAvailability, isChecking, error: availabilityError } = useUsernameAvailability(); const invitationUsername = (location.state as any)?.invitationUsername || ''; const invitationEmail = (location.state as any)?.invitationEmail || ''; @@ -118,7 +117,6 @@ function Register() { const _getErrorMessage = () => { if (validationError) return validationError; if (registerError) return typeof registerError === 'string' ? registerError : t('Registrierung fehlgeschlagen'); - if (msalError) return typeof msalError === 'string' ? msalError : t('Microsoft-Registrierung fehlgeschlagen'); if (availabilityError) return typeof availabilityError === 'string' ? availabilityError : t('Benutzernamen-Prüfung fehlgeschlagen'); return null; }; diff --git a/src/providers/auth/AuthProvider.tsx b/src/providers/auth/AuthProvider.tsx deleted file mode 100644 index c433e4b..0000000 --- a/src/providers/auth/AuthProvider.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { - AuthenticationResult, - EventType, - PublicClientApplication - } from "@azure/msal-browser"; - import { msalConfig } from "./authConfig"; - import { MsalProvider } from "@azure/msal-react"; - import { ReactNode, useEffect, useState } from "react"; - import { useLanguage } from "../language/LanguageContext"; - - interface AuthProviderProps { - children: ReactNode; - } - - export const AuthProvider = ({ children }: AuthProviderProps) => { - const { t } = useLanguage(); - const [msalInstance, setMsalInstance] = useState(null); - const [isInitialized, setIsInitialized] = useState(false); - - - useEffect(() => { - const msalApp = new PublicClientApplication(msalConfig); - - const initializeMsal = async () => { - try { - // Set event handlers first, so we catch all events - msalApp.addEventCallback((event) => { - if (event.eventType === EventType.LOGIN_SUCCESS) { - const payload = event?.payload as AuthenticationResult; - if (payload?.account) { - msalApp.setActiveAccount(payload.account); - console.log("MSAL login successful"); - - // Store authentication authority for backend communication - if (payload.account?.environment) { - sessionStorage.setItem('auth_authority', payload.account.environment); - } - - console.log('✅ MSAL login successful - tokens will be set in httpOnly cookies by backend'); - } - } else if (event.eventType === EventType.LOGIN_FAILURE) { - console.error("MSAL login failed:", event.error); - } - }); - - // Initialize MSAL - await msalApp.initialize(); - msalApp.enableAccountStorageEvents(); - - // Handle any redirect response - const response = await msalApp.handleRedirectPromise(); - if (response) { - // If we have a response, we've completed a redirect flow - console.log("MSAL redirect completed successfully"); - if (response.account) { - msalApp.setActiveAccount(response.account); - - // Store authentication authority - if (response.account.environment) { - sessionStorage.setItem('auth_authority', response.account.environment); - } - - console.log('✅ MSAL redirect completed - tokens will be set in httpOnly cookies by backend'); - } - } - - // Check for accounts - const accounts = msalApp.getAllAccounts(); - if (accounts.length > 0) { - msalApp.setActiveAccount(accounts[0]); - - // Store authentication authority for existing accounts - if (accounts[0].environment) { - sessionStorage.setItem('auth_authority', accounts[0].environment); - } - - console.log('✅ MSAL account found - tokens will be set in httpOnly cookies by backend'); - } - - setMsalInstance(msalApp); - setIsInitialized(true); - } catch (err) { - console.error("MSAL initialization failed", err); - } - }; - - initializeMsal(); - }, []); - - if (!isInitialized || !msalInstance) { - return
{t('Authentifizierung wird geladen…')}
; - } - - return {children}; - }; - - export function useAuthProvider() { - return { AuthProvider }; - } \ No newline at end of file diff --git a/src/providers/auth/ProtectedRoute.tsx b/src/providers/auth/ProtectedRoute.tsx index 12a57a7..1b9b42a 100644 --- a/src/providers/auth/ProtectedRoute.tsx +++ b/src/providers/auth/ProtectedRoute.tsx @@ -1,4 +1,3 @@ -import { useMsal } from "@azure/msal-react"; import { Navigate, useLocation } from "react-router-dom"; import { ReactNode, useEffect, useState } from "react"; import { useLanguage } from "../language/LanguageContext"; @@ -13,110 +12,36 @@ export const ProtectedRoute = ({ redirectPath = "/login" }: ProtectedRouteProps) => { const { t } = useLanguage(); - const { accounts } = useMsal(); const location = useLocation(); const [isChecking, setIsChecking] = useState(true); const [isAuthenticated, setIsAuthenticated] = useState(false); useEffect(() => { - const checkAuthentication = async () => { - try { - // Check for MSAL authentication - const hasMsalAccount = accounts.length > 0; - - // Check for backend authentication via API call - let hasBackendAuth = false; - - try { - // Check for authentication authority (httpOnly cookies are handled automatically) - const authAuthority = sessionStorage.getItem('auth_authority'); - console.log('🔍 Checking auth authority:', authAuthority); - - if (authAuthority) { - hasBackendAuth = true; - console.log('✅ Authenticated with backend (httpOnly cookies), authority:', authAuthority); - } else { - hasBackendAuth = false; - console.log('❌ No authentication authority found'); - } - } catch (error) { - console.log('❌ Backend authentication failed:', error); - hasBackendAuth = false; - } + const authAuthority = sessionStorage.getItem('auth_authority'); + setIsAuthenticated(!!authAuthority); + setIsChecking(false); + }, []); - // User is authenticated if either method is valid - const isAuth = hasMsalAccount || hasBackendAuth; - setIsAuthenticated(isAuth); - - console.log('🔐 Authentication status:', { - hasMsalAccount, - hasBackendAuth, - isAuthenticated: isAuth, - authAuthority: sessionStorage.getItem('auth_authority') - }); - - if (hasBackendAuth) { - console.log('✅ Authenticated with backend cookies'); - } else if (hasMsalAccount) { - console.log('✅ Authenticated with MSAL'); - } else { - console.log('❌ No valid authentication found'); - } - } catch (error) { - console.error('❌ Error checking authentication:', error); - setIsAuthenticated(false); - } finally { - setIsChecking(false); - } - }; - - // Small delay to ensure MSAL is initialized and localStorage is updated - const timer = setTimeout(() => { - checkAuthentication(); - }, 200); - - return () => clearTimeout(timer); - }, [accounts]); - - // Re-check authentication when component mounts or accounts change - // This handles cases where auth_authority is set after initial mount useEffect(() => { if (!isChecking) { - // Double-check authentication state periodically when not initially loading const recheckTimer = setTimeout(() => { const authAuthority = sessionStorage.getItem('auth_authority'); - const hasMsalAccount = accounts.length > 0; - const hasBackendAuth = !!authAuthority; - const isAuth = hasMsalAccount || hasBackendAuth; - - // Only update if authentication state actually changed + const isAuth = !!authAuthority; if (isAuth !== isAuthenticated) { - console.log('🔄 Authentication state changed, updating...', { - previous: isAuthenticated, - current: isAuth, - authAuthority, - hasMsalAccount, - hasBackendAuth - }); setIsAuthenticated(isAuth); } }, 300); - return () => clearTimeout(recheckTimer); } - }, [isChecking, isAuthenticated, accounts]); + }, [isChecking, isAuthenticated]); - // If still checking, show loading if (isChecking) { return
{t('Authentifizierung wird geprüft…')}
; } - // Check if user is authenticated through either method if (!isAuthenticated) { - console.log("No valid authentication found, redirecting to login"); return ; } - console.log("User is authenticated, rendering protected content"); return <>{children}; -}; \ No newline at end of file +}; diff --git a/src/providers/auth/authConfig.ts b/src/providers/auth/authConfig.ts deleted file mode 100644 index a06c7e8..0000000 --- a/src/providers/auth/authConfig.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { LogLevel } from '@azure/msal-browser'; - -export const msalConfig = { - auth: { - clientId: '24cd6c8a-b592-4905-a5ba-d5fa9f911154', - authority: 'https://login.microsoftonline.com/6a51aaeb-2467-4186-9504-2a05aedc591f/', - redirectUri: '/', - postLogoutRedirectUri: '/', - navigateToLoginRequestUrl: false, - }, - cache: { - cacheLocation: 'localStorage', - storeAuthStateInCookie: false, - }, - system: { - loggerOptions: { - loggerCallback: (level: any, message: any, containsPii: any) => { - if (containsPii) { - return; - } - switch (level) { - case LogLevel.Error: - console.error(message); - return; - case LogLevel.Info: - console.info(message); - return; - case LogLevel.Verbose: - console.debug(message); - return; - case LogLevel.Warning: - console.warn(message); - return; - default: - return; - } - }, - }, - }, -}; - - -export const loginRequest = { - scopes: ["openid", "profile", "email", "api://24cd6c8a-b592-4905-a5ba-d5fa9f911154/user_impersonation"], -}; \ No newline at end of file