frontend_nyla/docs/LOGIN_AND_PRIVILEGE_FLOW.md

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