Files
igny8/AUTHENTICATION-FIX-DEPLOYMENT.md
IGNY8 VPS (Salman) 4fb3a144d7 messy logout fixing
2025-12-15 12:01:41 +00:00

348 lines
8.3 KiB
Markdown

## 🚀 Authentication Fix - Deployment Guide
**IMPORTANT**: Follow these steps in order to avoid downtime.
---
## 📋 Pre-Deployment Checklist
- [ ] Backup database
- [ ] Review all changes in [AUTHENTICATION-FIX-IMPLEMENTATION.md](AUTHENTICATION-FIX-IMPLEMENTATION.md)
- [ ] Read [AUTHENTICATION-AUDIT-REPORT.md](AUTHENTICATION-AUDIT-REPORT.md) for context
- [ ] Ensure Redis is running
- [ ] Test in staging environment first (if available)
---
## 🔧 Step-by-Step Deployment
### Step 1: Install Backend Dependencies
```bash
cd /data/app/igny8/backend
pip install -r requirements.txt
# Specifically: django-redis>=5.4.0
```
### Step 2: Run Database Migrations
```bash
cd /data/app/igny8/backend
python manage.py makemigrations
python manage.py migrate
# You should see a new migration for RefreshToken model:
# - Create model RefreshToken
# - Add indexes
```
### Step 3: Verify Redis is Running
```bash
# Check Redis is accessible
redis-cli -h redis ping
# Should return: PONG
# Or check via Docker:
docker ps | grep redis
```
### Step 4: Test Backend Changes (Optional but Recommended)
```bash
cd /data/app/igny8/backend
python manage.py shell
# In the shell:
from igny8_core.auth.models_refresh_token import RefreshToken
from django.contrib.auth import get_user_model
User = get_user_model()
# Test token creation:
user = User.objects.first()
token = RefreshToken.create_token(user, remember_me=True)
print(f"Created token: {token.token_id}")
print(f"Expires: {token.expires_at}")
print(f"Valid: {token.is_valid}")
```
### Step 5: Restart Backend
```bash
cd /data/app/igny8
docker-compose -f docker-compose.app.yml restart igny8_backend
# Wait for healthy status:
docker-compose -f docker-compose.app.yml ps igny8_backend
```
### Step 6: Replace Frontend API Service
```bash
cd /data/app/igny8/frontend/src/services
# Backup old api.ts
cp api.ts api-old-backup.ts
# Replace with new implementation
mv api-new.ts api.ts
```
### Step 7: Update Frontend authStore (CRITICAL)
Open `frontend/src/store/authStore.ts` and make these changes:
#### 7a. Remove localStorage access_token persistence
Find and REMOVE these lines from login/register:
```typescript
// ❌ REMOVE THIS:
localStorage.setItem('access_token', newToken);
localStorage.setItem('refresh_token', newRefreshToken);
```
Access token should ONLY be in Zustand state (memory).
#### 7b. Update persist configuration
Ensure `partialize` does NOT include `token`:
```typescript
partialize: (state) => ({
user: state.user,
// ❌ DO NOT persist token: state.token,
refreshToken: state.refreshToken,
isAuthenticated: state.isAuthenticated,
})
```
#### 7c. Update refresh logic
Ensure refresh updates BOTH access and refresh tokens:
```typescript
// In refreshToken action:
const data = await response.json();
set({
token: data.data?.access || data.access,
refreshToken: data.data?.refresh || data.refresh // NEW: update refresh token too
});
```
#### 7d. Remove proactive refresh interval (Optional)
The new api.ts handles token refresh automatically on 401. Remove this from AppLayout.tsx:
```typescript
// ❌ REMOVE OR COMMENT OUT:
// const tokenRefreshInterval = setInterval(async () => {
// await authState.refreshToken();
// }, 720000);
```
### Step 8: Add Remember-Me Checkbox to Login Form
Open your login form component (e.g., `pages/SignIn.tsx`) and add:
```typescript
// Add state:
const [rememberMe, setRememberMe] = useState(false);
// Add checkbox before submit button:
<label className="flex items-center gap-2">
<input
type="checkbox"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
className="form-checkbox"
/>
<span>Keep me logged in for 20 days</span>
</label>
// Update login call:
await login(email, password, rememberMe);
```
Update authStore login method signature:
```typescript
login: async (email: string, password: string, rememberMe = false) => {
// ...
body: JSON.stringify({ email, password, remember_me: rememberMe }),
// ...
}
```
### Step 9: Rebuild and Restart Frontend
```bash
cd /data/app/igny8/frontend
docker-compose -f ../docker-compose.app.yml restart igny8_frontend
# Or rebuild if needed:
docker build -t igny8-frontend-dev:latest -f Dockerfile.dev .
docker-compose -f ../docker-compose.app.yml up -d igny8_frontend
```
### Step 10: Verify Everything Works
#### Test 1: Fresh Login
1. Clear browser cache and cookies
2. Navigate to login page
3. Login with remember-me checked
4. Verify you stay logged in
5. Check Redis: `redis-cli keys "*"` should show session
#### Test 2: Token Refresh
1. Login
2. Wait 1 hour (access token expires)
3. Make an API call
4. Should automatically refresh and succeed
5. Check network tab - should see refresh call
#### Test 3: Multi-Tab
1. Open app in two tabs
2. Trigger token refresh in one tab
3. Make API call in other tab
4. Should work without re-auth
#### Test 4: Error Handling
1. Login
2. Trigger a 403 error (access denied page)
3. Verify you are NOT logged out
4. Navigate to dashboard - should still work
#### Test 5: Logout
1. Login
2. Click logout
3. Verify all tabs logout
4. Check Redis - session should be gone
---
## 🐛 Troubleshooting
### "RefreshToken model not found"
```bash
cd /data/app/igny8/backend
python manage.py migrate
```
### "Redis connection refused"
```bash
# Check Redis is running:
docker ps | grep redis
docker-compose -f docker-compose.app.yml ps
# Restart Redis:
cd /data/app
docker-compose -f docker-compose.yml restart redis
```
### "django-redis not installed"
```bash
cd /data/app/igny8/backend
pip install django-redis>=5.4.0
docker-compose -f docker-compose.app.yml restart igny8_backend
```
### "Still getting logged out on 403 errors"
- Check that `frontend/src/services/api.ts` is the NEW version
- Old api.ts has logout on 403, new one doesn't
- Verify file was replaced: `grep "NEVER logout on 403" frontend/src/services/api.ts`
### "Token refresh not working"
- Check backend logs: `docker logs igny8_backend -f`
- Verify RefreshToken records in database
- Check that refresh endpoint returns new refresh token
### "Multi-tab logout"
- Verify BroadcastChannel is supported (Chrome/Firefox/Edge)
- Check browser console for errors
- Fallback: Polling localStorage for token changes
---
## 📊 Monitoring Post-Deployment
### Key Metrics to Watch:
1. **Logout rate**: Should drop to near-zero (except explicit logouts)
2. **Token refresh success rate**: Should be >99.9%
3. **403 errors**: Should NOT cause logout
4. **Session duration**: Average should increase to ~20 days with remember-me
### Database Queries:
```sql
-- Check active refresh tokens
SELECT COUNT(*) FROM auth_refresh_token WHERE revoked_at IS NULL AND expires_at > NOW();
-- Check token rotation (should increase over time)
SELECT AVG(rotation_count) FROM auth_refresh_token WHERE created_at > NOW() - INTERVAL '7 days';
-- Check remember-me usage
SELECT
remember_me,
COUNT(*) as count,
AVG(EXTRACT(EPOCH FROM (expires_at - created_at))/86400) as avg_days
FROM auth_refresh_token
WHERE created_at > NOW() - INTERVAL '7 days'
GROUP BY remember_me;
```
---
## 🔄 Rollback Plan (If Needed)
If something goes wrong:
### 1. Restore old api.ts:
```bash
cd /data/app/igny8/frontend/src/services
mv api.ts api-new-broken.ts
mv api-old-backup.ts api.ts
```
### 2. Revert settings.py changes:
```python
# Change back:
SESSION_COOKIE_SAMESITE = 'Strict'
SESSION_SAVE_EVERY_REQUEST = False
JWT_ACCESS_TOKEN_EXPIRY = timedelta(minutes=15)
# Comment out Redis cache config
```
### 3. Revert middleware.py:
- Add `from django.contrib.auth import logout` back
- Restore logout calls in validation failures
### 4. Restart services:
```bash
docker-compose -f docker-compose.app.yml restart igny8_backend igny8_frontend
```
---
## ✅ Success Indicators
You'll know the fix is working when:
- ✅ Users report no random logouts
- ✅ Remember-me users stay logged in for 20 days
- ✅ 403/402 errors don't log users out
- ✅ Network hiccups don't cause logout
- ✅ Multi-tab usage works smoothly
- ✅ Token refresh is invisible to users
---
## 📞 Support
If you encounter issues:
1. Check logs: `docker logs igny8_backend -f`
2. Review error messages in browser console
3. Verify migrations ran successfully
4. Check Redis connectivity
5. Test with fresh user account
---
**Last Updated:** December 15, 2025
**Estimated Deployment Time:** 30-45 minutes
**Risk Level:** Low (all changes backward compatible)