319 lines
12 KiB
Markdown
319 lines
12 KiB
Markdown
# 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:**
|
|
1. **User profile language** (from `localStorage('currentUser').language` - synced from backend)
|
|
2. **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`)**
|
|
```typescript
|
|
// 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')`:
|
|
|
|
```typescript
|
|
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 users
|
|
- `privilegeCheckers.sysadminRole` - For sysadmin only
|
|
- `privilegeCheckers.userRole` - For user, admin, and sysadmin
|
|
- `privilegeCheckers.viewerRole` - For all authenticated users
|
|
- `privilegeCheckers.speechSignup` - For speech feature access
|
|
- `privilegeCheckers.alwaysAllow` - For public pages
|
|
- `privilegeCheckers.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:
|
|
|
|
1. **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)
|
|
|
|
2. **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)
|
|
|
|
3. **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)
|
|
|
|
4. **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:
|
|
|
|
1. **OAuth Cookie Delay**: Microsoft and Google auth have a 500ms delay before fetching user data to ensure cookies are properly set by the browser.
|
|
|
|
2. **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.
|
|
|
|
3. **Cache Strategy**: User data is cached in localStorage for instant access, but is also refreshed on each page load via `useCurrentUser()` hook.
|
|
|
|
4. **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:
|
|
|
|
1. **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
|
|
```
|
|
|
|
2. **Language Test:**
|
|
```
|
|
- Log in
|
|
- Check console for: "🌍 Using language from user data: [language]"
|
|
- Change language in settings
|
|
- Verify UI updates immediately
|
|
```
|
|
|
|
3. **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 fetch
|
|
- `src/hooks/useUsers.ts` - User data management
|
|
- `src/contexts/LanguageContext.tsx` - Language management
|
|
- `src/core/PageManager/PageManager.tsx` - Page routing and privilege checking
|
|
- `src/core/PageManager/PageRenderer.tsx` - Page rendering with language
|
|
- `src/utils/privilegeCheckers.ts` - Privilege checking utilities
|
|
- `src/pages/Home/Home.tsx` - Main application entry after login
|
|
|