12 KiB
Login and Privilege Flow Documentation
Overview
This document describes the complete login flow, including user data fetching, privilege checking, and language synchronization.
Updated Login Flow (Post-Fix)
1. Login Process
Local Authentication (useAuth in useAuthentication.ts)
User enters credentials → POST /api/local/login → Success
↓
✅ Tokens stored in httpOnly cookies
✅ authenticationAuthority saved to localStorage
↓
🔄 IMMEDIATE user data fetch: GET /api/local/me
↓
✅ User data cached in localStorage ('currentUser')
- Includes: username, privilege, language, etc.
- Language is part of user data (NO separate storage!)
↓
Navigate to Home page
Microsoft Authentication (useMsalAuth in useAuthentication.ts)
User clicks Microsoft login → Popup opens → Microsoft OAuth flow
↓
✅ Tokens stored in httpOnly cookies
✅ authenticationAuthority saved to localStorage
↓
⏳ Wait 500ms for cookie propagation
↓
🔄 IMMEDIATE user data fetch: GET /api/msft/me
↓
✅ User data cached in localStorage ('currentUser')
✅ Language setting synced to localStorage ('language')
↓
Navigate to Home page
Google Authentication (useGoogleAuth in useAuthentication.ts)
User clicks Google login → Popup opens → Google OAuth flow
↓
✅ Tokens stored in httpOnly cookies
✅ authenticationAuthority saved to localStorage
↓
⏳ Wait 500ms for cookie propagation
↓
🔄 IMMEDIATE user data fetch: GET /api/google/me
↓
✅ User data cached in localStorage ('currentUser')
✅ Language setting synced to localStorage ('language')
↓
Navigate to Home page
2. Home Page Load (Home.tsx)
Home page mounts
↓
useCurrentUser() hook called
↓
Checks localStorage for cached user data
↓
If cached: Uses cached data (instant)
If not cached: Fetches from API (with loading state)
↓
User data available
↓
PageManager receives user data context
3. Language Synchronization (LanguageContext.tsx)
The language context now follows a priority system:
Priority Order:
- User profile language (from
localStorage('currentUser').language- synced from backend) - Browser language (from
navigator.language- fallback if no user data)
Language Loading:
LanguageProvider mounts
↓
Check currentUser in localStorage
↓
If user.language exists: Use user.language ✅
↓
Else: Use browser language (fallback)
↓
Load translations for selected language
Language Updates (Settings Flow):
User changes language in settings
↓
1. Update backend user profile (PUT /api/users/{id})
↓
2. Backend returns updated user data
↓
3. Update localStorage('currentUser') with new data ✅
↓
4. Call setLanguage() to load new translations
↓
5. Trigger 'userInfoUpdated' event
↓
LanguageContext syncs and UI updates
4. Privilege Checking System
Where Privileges Are Checked:
A. Page Level (PageManager.tsx)
// Line 29-40 in PageManager.tsx
const checkPageAccess = async (pageData: GenericPageData): Promise<boolean> => {
if (!pageData.privilegeChecker) {
return true; // No checker = accessible to all
}
try {
return await pageData.privilegeChecker();
} catch (error) {
console.error(`Error checking page access for ${pageData.path}:`, error);
return false;
}
};
B. Privilege Checkers (privilegeCheckers.ts)
All privilege checkers read from localStorage.getItem('currentUser'):
const getCurrentUserPrivilege = (): string | null => {
try {
const userData = localStorage.getItem('currentUser');
if (userData) {
const user = JSON.parse(userData);
return user.privilege || null;
}
return null;
} catch (error) {
console.error('Error getting user privilege:', error);
return null;
}
};
Available Privilege Checkers:
privilegeCheckers.adminRole- For admin and sysadmin usersprivilegeCheckers.sysadminRole- For sysadmin onlyprivilegeCheckers.userRole- For user, admin, and sysadminprivilegeCheckers.viewerRole- For all authenticated usersprivilegeCheckers.speechSignup- For speech feature accessprivilegeCheckers.alwaysAllow- For public pagesprivilegeCheckers.neverAllow- For disabled features
Privilege Check Flow:
PageManager renders page
↓
checkPageAccess(pageData)
↓
pageData.privilegeChecker() called
↓
Reads from localStorage('currentUser')
↓
Checks user.privilege against required privileges
↓
Returns true/false
↓
If true: Page renders
If false: Error component shows
5. Complete Flow Diagram
┌─────────────────────────────────────────────────────────────┐
│ LOGIN │
│ (Local/Microsoft/Google) │
└──────────────────┬──────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ ✅ Set httpOnly cookies (backend) │
│ ✅ Save auth_authority to localStorage │
│ 🔄 IMMEDIATELY fetch user data: GET /api/*/me │
│ ✅ Cache user data in localStorage('currentUser') │
│ ✅ Sync language to localStorage('language') │
└──────────────────┬──────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Navigate to Home │
└──────────────────┬──────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ Home.tsx Mounts │
│ - useCurrentUser() → Reads from localStorage (instant!) │
│ - LanguageProvider → Reads user.language (instant!) │
└──────────────────┬──────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ PageManager Renders │
│ - Gets currentLanguage from LanguageContext │
│ - Checks page privileges (reads from localStorage) │
│ - Passes language to PageRenderer │
└──────────────────┬──────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ PageRenderer Displays Page │
│ - Uses user's language for all text │
│ - All privilege checks use cached user data │
└─────────────────────────────────────────────────────────────┘
Key Changes Made
✅ Fixed Issues:
-
User data is now fetched IMMEDIATELY after login
- Previously: Fetched only when Home.tsx mounted
- Now: Fetched right after successful authentication
- Location:
src/hooks/useAuthentication.ts(lines 65-88 for local, 258-297 for Microsoft, 727-753 for Google)
-
Language is synced from user profile
- Previously: Loaded from localStorage or browser only
- Now: Prioritizes user.language from API response
- Location:
src/contexts/LanguageContext.tsx(lines 42-108)
-
Language is passed to PageRenderer
- Previously: Default 'de' was used
- Now: Current language from context is passed
- Location:
src/core/PageManager/PageManager.tsx(line 104)
-
Privilege checks use cached user data
- User data is available immediately in localStorage
- No race conditions between page load and user data fetch
- Location:
src/utils/privilegeCheckers.ts(lines 4-21)
📝 Important Notes:
-
OAuth Cookie Delay: Microsoft and Google auth have a 500ms delay before fetching user data to ensure cookies are properly set by the browser.
-
Error Handling: If user data fetch fails after login, the user is still navigated to the home page, but will see a loading/error state there.
-
Cache Strategy: User data is cached in localStorage for instant access, but is also refreshed on each page load via
useCurrentUser()hook. -
Language Updates: When a user updates their language in settings, the system:
- Updates backend user profile
- Triggers 'userInfoUpdated' event
- LanguageContext listens and syncs the new language
- All components using
useLanguage()automatically update
API Endpoints Used
| Endpoint | Purpose | When Called |
|---|---|---|
POST /api/local/login |
Local authentication | User submits login form |
GET /api/local/me |
Get current user (local) | Immediately after local login + on Home.tsx mount |
GET /api/msft/me |
Get current user (Microsoft) | Immediately after Microsoft login + on Home.tsx mount |
GET /api/google/me |
Get current user (Google) | Immediately after Google login + on Home.tsx mount |
Testing the Flow
To verify the flow is working correctly:
-
Login Test:
- Clear localStorage - Log in with any method - Check console for: "🔄 Fetching user data immediately after login..." - Check console for: "✅ User data fetched and cached" - Verify localStorage has 'currentUser' and 'language' keys -
Language Test:
- Log in - Check console for: "🌍 Using language from user data: [language]" - Change language in settings - Verify UI updates immediately -
Privilege Test:
- Log in as user with different privilege levels - Navigate to admin pages - Verify access based on privilege - Check console for: "🔍 Checking role privilege" logs
Troubleshooting
Issue: Pages show "Access denied" after login
Solution: Check if user data is properly cached in localStorage. Look for console errors in user data fetch.
Issue: Wrong language is displayed
Solution: Verify that user.language exists in the API response. Check browser console for language loading logs.
Issue: OAuth login doesn't fetch user data
Solution: Check if the 500ms delay is sufficient for your environment. Increase delay if needed in useAuthentication.ts.
Related Files
src/hooks/useAuthentication.ts- Login logic and immediate user fetchsrc/hooks/useUsers.ts- User data managementsrc/contexts/LanguageContext.tsx- Language managementsrc/core/PageManager/PageManager.tsx- Page routing and privilege checkingsrc/core/PageManager/PageRenderer.tsx- Page rendering with languagesrc/utils/privilegeCheckers.ts- Privilege checking utilitiessrc/pages/Home/Home.tsx- Main application entry after login