Initial commit: Family Planner application
Complete family planning application with: - React frontend with TypeScript - Node.js/Express backend with TypeScript - Python ingestion service for document processing - Planning ingestion service with LLM integration - Shared UI components and type definitions - OAuth integration for calendar synchronization - Comprehensive documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
282
docs/archive/CORRECTIONS_OAUTH.md
Normal file
282
docs/archive/CORRECTIONS_OAUTH.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# Corrections apportées au système OAuth
|
||||
|
||||
## Problème initial
|
||||
|
||||
**Erreur rencontrée** :
|
||||
```
|
||||
Accès bloqué : erreur d'autorisation
|
||||
Required parameter is missing: response_type
|
||||
Erreur 400 : invalid_request
|
||||
flowName=GeneralOAuthFlow
|
||||
```
|
||||
|
||||
**Cause** : L'URL OAuth générée était incomplète. Elle ne contenait que l'URL de base et le paramètre `state`, mais manquait tous les paramètres requis par OAuth 2.0 :
|
||||
- `client_id`
|
||||
- `redirect_uri`
|
||||
- `response_type` ⚠️ **CRITIQUE**
|
||||
- `scope`
|
||||
- `access_type` (pour Google)
|
||||
- `prompt` (pour Google)
|
||||
|
||||
## Corrections effectuées
|
||||
|
||||
### 1. Fichier manquant
|
||||
✅ **Copié** `calendar.ts` du mauvais emplacement vers le bon :
|
||||
- Source : `C:\Users\philh\OneDrive\Documents\Codes\backend\src\routes\calendar.ts`
|
||||
- Destination : `C:\Users\philh\OneDrive\Documents\Codes\family-planner\backend\src\routes\calendar.ts`
|
||||
|
||||
### 2. URL OAuth complète (ligne 48-82)
|
||||
|
||||
**AVANT** (incorrect) :
|
||||
```typescript
|
||||
const authUrl = `${baseUrls[provider]}?state=${encodeURIComponent(state)}`;
|
||||
```
|
||||
|
||||
**APRÈS** (correct) :
|
||||
```typescript
|
||||
// Google
|
||||
const params = new URLSearchParams({
|
||||
client_id: config.clientId,
|
||||
redirect_uri: config.redirectUri,
|
||||
response_type: "code", // ⚠️ PARAMÈTRE MANQUANT
|
||||
scope: config.scope,
|
||||
state: state,
|
||||
access_type: "offline",
|
||||
prompt: "consent"
|
||||
});
|
||||
authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
||||
|
||||
// Outlook
|
||||
const params = new URLSearchParams({
|
||||
client_id: config.clientId,
|
||||
redirect_uri: config.redirectUri,
|
||||
response_type: "code", // ⚠️ PARAMÈTRE MANQUANT
|
||||
scope: config.scope,
|
||||
state: state,
|
||||
response_mode: "query"
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Configuration centralisée
|
||||
|
||||
Ajout d'un objet `OAUTH_CONFIG` avec :
|
||||
- Client IDs
|
||||
- Redirect URIs
|
||||
- Scopes appropriés pour chaque provider
|
||||
|
||||
### 4. Variables d'environnement
|
||||
|
||||
Ajout dans `backend/.env` :
|
||||
```env
|
||||
# OAuth Configuration - Google Calendar
|
||||
GOOGLE_CLIENT_ID=your_google_client_id_here
|
||||
GOOGLE_CLIENT_SECRET=your_google_client_secret_here
|
||||
GOOGLE_REDIRECT_URI=http://localhost:5000/api/calendar/oauth/callback
|
||||
|
||||
# OAuth Configuration - Outlook/Microsoft 365
|
||||
OUTLOOK_CLIENT_ID=your_outlook_client_id_here
|
||||
OUTLOOK_CLIENT_SECRET=your_outlook_client_secret_here
|
||||
OUTLOOK_REDIRECT_URI=http://localhost:5000/api/calendar/oauth/callback
|
||||
```
|
||||
|
||||
### 5. Documentation complète
|
||||
|
||||
Créé `OAUTH_SETUP.md` avec :
|
||||
- Instructions étape par étape pour Google Cloud Console
|
||||
- Instructions étape par étape pour Azure Portal
|
||||
- Configuration des scopes
|
||||
- Résolution des problèmes courants
|
||||
- Mode développement sans OAuth
|
||||
|
||||
## Prochaines étapes requises
|
||||
|
||||
### Étape 1 : Configurer les identifiants OAuth (VOUS)
|
||||
|
||||
Suivez le guide `OAUTH_SETUP.md` pour :
|
||||
1. ✅ Créer un projet Google Cloud
|
||||
2. ✅ Activer l'API Google Calendar
|
||||
3. ✅ Créer les identifiants OAuth 2.0
|
||||
4. ✅ Copier le Client ID et Secret dans `.env`
|
||||
5. ✅ Répéter pour Azure AD (Outlook)
|
||||
|
||||
### Étape 2 : Implémenter l'échange de code (DÉVELOPPEMENT)
|
||||
|
||||
Actuellement, le endpoint `/oauth/complete` crée une connexion factice. Il faut :
|
||||
|
||||
```typescript
|
||||
// Échanger le code d'autorisation contre un access token
|
||||
const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
code: code,
|
||||
client_id: OAUTH_CONFIG.google.clientId,
|
||||
client_secret: OAUTH_CONFIG.google.clientSecret,
|
||||
redirect_uri: OAUTH_CONFIG.google.redirectUri,
|
||||
grant_type: "authorization_code"
|
||||
})
|
||||
});
|
||||
|
||||
const tokens = await tokenResponse.json();
|
||||
// tokens.access_token, tokens.refresh_token, tokens.expires_in
|
||||
```
|
||||
|
||||
### Étape 3 : Stocker les tokens de manière sécurisée
|
||||
|
||||
**⚠️ NE JAMAIS stocker en clair** :
|
||||
- Utiliser un chiffrement AES-256-GCM (comme dans l'architecture PRONOTE)
|
||||
- Stocker la clé de chiffrement dans une variable d'environnement
|
||||
- Stocker les tokens dans une base de données ou fichier chiffré
|
||||
|
||||
### Étape 4 : Implémenter le refresh token
|
||||
|
||||
Les access tokens expirent (généralement 1h). Implémenter :
|
||||
```typescript
|
||||
async function refreshAccessToken(refreshToken: string, provider: CalendarProvider) {
|
||||
const config = OAUTH_CONFIG[provider];
|
||||
const response = await fetch(tokenEndpoint, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
refresh_token: refreshToken,
|
||||
client_id: config.clientId,
|
||||
client_secret: config.clientSecret,
|
||||
grant_type: "refresh_token"
|
||||
})
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
```
|
||||
|
||||
### Étape 5 : Récupérer les événements du calendrier
|
||||
|
||||
Une fois l'access token obtenu :
|
||||
|
||||
**Google Calendar API** :
|
||||
```typescript
|
||||
const events = await fetch(
|
||||
"https://www.googleapis.com/calendar/v3/calendars/primary/events",
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
**Microsoft Graph API** :
|
||||
```typescript
|
||||
const events = await fetch(
|
||||
"https://graph.microsoft.com/v1.0/me/calendar/events",
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Étape 6 : Normaliser les événements
|
||||
|
||||
Créer un format commun pour les événements des deux providers :
|
||||
```typescript
|
||||
type NormalizedEvent = {
|
||||
id: string;
|
||||
title: string;
|
||||
start: string; // ISO8601
|
||||
end: string; // ISO8601
|
||||
description?: string;
|
||||
location?: string;
|
||||
attendees?: string[];
|
||||
source: "google" | "outlook";
|
||||
originalId: string;
|
||||
};
|
||||
```
|
||||
|
||||
## État actuel
|
||||
|
||||
✅ **Corrigé** : Erreur OAuth "response_type missing"
|
||||
✅ **Ajouté** : Configuration complète des paramètres OAuth
|
||||
✅ **Documenté** : Guide de setup détaillé
|
||||
⏳ **À faire** : Configuration des identifiants OAuth par l'utilisateur
|
||||
⏳ **À faire** : Implémentation complète du flow OAuth (échange de code, stockage sécurisé, refresh)
|
||||
⏳ **À faire** : Récupération et synchronisation des événements
|
||||
|
||||
## Sécurité - Points d'attention
|
||||
|
||||
### ⚠️ CRITIQUE - À corriger immédiatement
|
||||
|
||||
1. **Clé OpenAI exposée dans Git** :
|
||||
- La clé `sk-proj-efaTQ8cicJYU7k8RG...` est visible dans `.env`
|
||||
- **ACTION REQUISE** : Révoquer immédiatement sur https://platform.openai.com/api-keys
|
||||
|
||||
2. **Tokens en mémoire** :
|
||||
- Actuellement, les connexions sont stockées dans une `Map` en mémoire
|
||||
- Problème : perte des données au redémarrage du serveur
|
||||
- **Solution** : Stocker dans une base de données chiffrée
|
||||
|
||||
3. **Secrets en clair** :
|
||||
- Les client secrets doivent être dans `.env` (qui doit être dans `.gitignore`)
|
||||
- **Vérifier** que `.env` est bien ignoré par Git
|
||||
|
||||
### Recommandations de sécurité
|
||||
|
||||
```typescript
|
||||
// Implémenter le chiffrement des tokens
|
||||
import crypto from "crypto";
|
||||
|
||||
const ENCRYPTION_KEY = process.env.TOKEN_ENCRYPTION_KEY; // 32 bytes
|
||||
const algorithm = "aes-256-gcm";
|
||||
|
||||
function encryptToken(token: string): { encrypted: string; iv: string; authTag: string } {
|
||||
const iv = crypto.randomBytes(16);
|
||||
const cipher = crypto.createCipheriv(algorithm, Buffer.from(ENCRYPTION_KEY, "hex"), iv);
|
||||
let encrypted = cipher.update(token, "utf8", "hex");
|
||||
encrypted += cipher.final("hex");
|
||||
const authTag = cipher.getAuthTag();
|
||||
return {
|
||||
encrypted,
|
||||
iv: iv.toString("hex"),
|
||||
authTag: authTag.toString("hex")
|
||||
};
|
||||
}
|
||||
|
||||
function decryptToken(encrypted: string, iv: string, authTag: string): string {
|
||||
const decipher = crypto.createDecipheriv(
|
||||
algorithm,
|
||||
Buffer.from(ENCRYPTION_KEY, "hex"),
|
||||
Buffer.from(iv, "hex")
|
||||
);
|
||||
decipher.setAuthTag(Buffer.from(authTag, "hex"));
|
||||
let decrypted = decipher.update(encrypted, "hex", "utf8");
|
||||
decrypted += decipher.final("utf8");
|
||||
return decrypted;
|
||||
}
|
||||
```
|
||||
|
||||
## Test de la correction
|
||||
|
||||
Pour tester que l'erreur OAuth est corrigée :
|
||||
|
||||
1. Redémarrez le backend :
|
||||
```bash
|
||||
cd backend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
2. Dans le frontend, testez la connexion Google/Outlook
|
||||
|
||||
3. Vérifiez que l'URL de redirection contient maintenant tous les paramètres :
|
||||
```
|
||||
https://accounts.google.com/o/oauth2/v2/auth?
|
||||
client_id=...&
|
||||
redirect_uri=...&
|
||||
response_type=code& ← AJOUTÉ
|
||||
scope=...&
|
||||
state=...&
|
||||
access_type=offline& ← AJOUTÉ
|
||||
prompt=consent ← AJOUTÉ
|
||||
```
|
||||
|
||||
4. Vous devriez voir la page de consentement Google/Microsoft (au lieu de l'erreur 400)
|
||||
|
||||
**Note** : Vous aurez une erreur de "client_id invalide" tant que vous n'aurez pas configuré les vrais identifiants OAuth dans le `.env`.
|
||||
Reference in New Issue
Block a user