mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
Merge pull request #40 from R0m1k3/claude/fix-redirect-uri-mismatch-011CV41yPYKHVkiwiBSZ2sd3
Feature: Ajout du support OAuth2 et Service Account pour Google Calendar
This commit is contained in:
4 files changed
+415
-65
No files matched your search
+120
-4
@@ -1,6 +1,25 @@
|
||||
# Configuration OAuth Google Calendar
|
||||
# Configuration Google Calendar
|
||||
|
||||
Ce guide vous aide à résoudre les erreurs d'authentification OAuth Google.
|
||||
Ce guide vous aide à configurer l'accès à Google Calendar avec deux méthodes disponibles : **OAuth 2.0** et **Service Account**.
|
||||
|
||||
## Choisir la bonne méthode
|
||||
|
||||
### OAuth 2.0 (Recommandé pour usage personnel)
|
||||
- ✅ Accès au calendrier personnel de l'utilisateur
|
||||
- ✅ Sécurisé avec consentement explicite
|
||||
- ✅ Choix du compte Google à la connexion
|
||||
- ⚠️ Nécessite une interaction utilisateur (popup de consentement)
|
||||
|
||||
### Service Account (Pour applications automatisées)
|
||||
- ✅ Aucune interaction utilisateur requise
|
||||
- ✅ Idéal pour calendriers partagés en entreprise
|
||||
- ✅ Fonctionne en arrière-plan
|
||||
- ⚠️ Nécessite de partager le calendrier avec le Service Account
|
||||
- ⚠️ Configuration plus technique
|
||||
|
||||
---
|
||||
|
||||
# Configuration OAuth 2.0
|
||||
|
||||
## Problème : Erreur 400 - redirect_uri_mismatch
|
||||
|
||||
@@ -86,10 +105,107 @@ Si vous ne voyez toujours pas le choix du compte :
|
||||
- [ ] Application redémarrée après modification du `.env`
|
||||
- [ ] Attendu 5-10 minutes après modification dans Google Cloud Console
|
||||
|
||||
---
|
||||
|
||||
# Configuration Service Account
|
||||
|
||||
Le Service Account permet un accès automatisé sans interaction utilisateur, idéal pour des calendriers partagés.
|
||||
|
||||
## Étapes de configuration
|
||||
|
||||
### 1. Créer un Service Account
|
||||
|
||||
1. Allez sur [Google Cloud Console - Service Accounts](https://console.cloud.google.com/iam-admin/serviceaccounts)
|
||||
|
||||
2. Sélectionnez votre projet (ou créez-en un nouveau)
|
||||
|
||||
3. Cliquez sur **"+ CREATE SERVICE ACCOUNT"**
|
||||
|
||||
4. Donnez un nom au compte (ex: `noteflow-calendar`)
|
||||
|
||||
5. Cliquez sur **"CREATE AND CONTINUE"**
|
||||
|
||||
6. Sautez les étapes optionnelles et cliquez sur **"DONE"**
|
||||
|
||||
### 2. Générer une clé JSON
|
||||
|
||||
1. Dans la liste des Service Accounts, cliquez sur celui que vous venez de créer
|
||||
|
||||
2. Allez dans l'onglet **"KEYS"**
|
||||
|
||||
3. Cliquez sur **"ADD KEY"** > **"Create new key"**
|
||||
|
||||
4. Choisissez le format **JSON**
|
||||
|
||||
5. Téléchargez le fichier JSON (conservez-le en sécurité !)
|
||||
|
||||
### 3. Activer l'API Google Calendar
|
||||
|
||||
1. Allez sur [Google Cloud Console - API Library](https://console.cloud.google.com/apis/library)
|
||||
|
||||
2. Recherchez **"Google Calendar API"**
|
||||
|
||||
3. Cliquez sur **"ENABLE"**
|
||||
|
||||
### 4. Partager votre calendrier
|
||||
|
||||
1. Ouvrez [Google Calendar](https://calendar.google.com)
|
||||
|
||||
2. Trouvez votre calendrier dans la liste à gauche
|
||||
|
||||
3. Cliquez sur les **3 points** à côté du nom du calendrier
|
||||
|
||||
4. Sélectionnez **"Paramètres et partage"**
|
||||
|
||||
5. Faites défiler jusqu'à **"Partager avec des personnes en particulier"**
|
||||
|
||||
6. Cliquez sur **"+ Ajouter des personnes"**
|
||||
|
||||
7. Collez l'**email du Service Account** (trouvé dans le fichier JSON, champ `client_email`)
|
||||
|
||||
8. Donnez les permissions **"Afficher tous les détails des événements"**
|
||||
|
||||
9. Cliquez sur **"Envoyer"**
|
||||
|
||||
### 5. Configurer NoteFlow
|
||||
|
||||
1. Dans NoteFlow, allez dans **Administration** > **Google Calendar**
|
||||
|
||||
2. Sélectionnez **"Service Account"** dans le menu déroulant
|
||||
|
||||
3. Ouvrez le fichier JSON téléchargé et **copiez tout son contenu**
|
||||
|
||||
4. Collez le contenu dans le champ **"Clé Service Account (JSON)"**
|
||||
|
||||
5. Entrez votre email (celui du calendrier partagé) dans **"Email du calendrier à synchroniser"**
|
||||
|
||||
6. Cliquez sur **"Enregistrer"**
|
||||
|
||||
7. Cliquez sur **"Synchroniser"** pour tester
|
||||
|
||||
## Dépannage Service Account
|
||||
|
||||
### Erreur : "Clé Service Account invalide"
|
||||
- Vérifiez que vous avez copié l'intégralité du fichier JSON
|
||||
- Assurez-vous qu'il n'y a pas d'espaces ou de caractères en trop
|
||||
|
||||
### Erreur : "Calendar not found" ou "Permission denied"
|
||||
- Vérifiez que vous avez bien partagé le calendrier avec l'email du Service Account
|
||||
- Vérifiez que l'email du calendrier est correct
|
||||
- Attendez quelques minutes après avoir partagé le calendrier
|
||||
|
||||
### Les événements ne se synchronisent pas
|
||||
- Vérifiez que l'API Google Calendar est activée dans votre projet
|
||||
- Vérifiez les logs de l'application pour plus de détails
|
||||
- Assurez-vous que le Service Account a les bonnes permissions
|
||||
|
||||
---
|
||||
|
||||
## Besoin d'aide ?
|
||||
|
||||
Si le problème persiste :
|
||||
1. Vérifiez les logs de l'application pour des messages d'erreur détaillés
|
||||
2. Assurez-vous que votre navigateur accepte les cookies tiers
|
||||
3. Essayez en navigation privée pour éliminer les problèmes de cache
|
||||
2. Pour OAuth 2.0 : Assurez-vous que votre navigateur accepte les cookies tiers
|
||||
3. Pour OAuth 2.0 : Essayez en navigation privée pour éliminer les problèmes de cache
|
||||
4. Vérifiez que l'API Google Calendar est bien activée dans votre projet Google Cloud
|
||||
5. Pour Service Account : Vérifiez que le calendrier est bien partagé avec le bon email
|
||||
@@ -0,0 +1,68 @@
|
||||
# Google Calendar - Deux méthodes d'authentification
|
||||
|
||||
NoteFlow supporte maintenant **deux méthodes** pour se connecter à Google Calendar :
|
||||
|
||||
## 🔐 OAuth 2.0 (Recommandé pour usage personnel)
|
||||
**Avantages** :
|
||||
- Accès sécurisé à votre calendrier personnel
|
||||
- Choix du compte Google lors de la connexion
|
||||
- Consentement explicite de l'utilisateur
|
||||
|
||||
**Utilisation** : Administration > Google Calendar > Méthode : OAuth 2.0
|
||||
|
||||
[📖 Guide complet OAuth 2.0](./OAUTH_SETUP.md#configuration-oauth-20)
|
||||
|
||||
---
|
||||
|
||||
## 🤖 Service Account (Pour automatisation)
|
||||
**Avantages** :
|
||||
- Aucune interaction utilisateur requise
|
||||
- Parfait pour calendriers partagés en entreprise
|
||||
- Fonctionne en arrière-plan automatiquement
|
||||
|
||||
**Utilisation** : Administration > Google Calendar > Méthode : Service Account
|
||||
|
||||
[📖 Guide complet Service Account](./OAUTH_SETUP.md#configuration-service-account)
|
||||
|
||||
---
|
||||
|
||||
## Problèmes courants résolus
|
||||
|
||||
### ✅ Erreur 400 : redirect_uri_mismatch
|
||||
- Variable `APP_URL` ajoutée dans `.env.example`
|
||||
- Guide de configuration détaillé dans OAUTH_SETUP.md
|
||||
|
||||
### ✅ Pas de choix de compte Google
|
||||
- Le prompt `select_account` force maintenant l'affichage du sélecteur
|
||||
|
||||
### ✅ Besoin d'accès automatisé sans popup
|
||||
- Utilisez Service Account pour une authentification sans interaction
|
||||
|
||||
---
|
||||
|
||||
## Configuration rapide
|
||||
|
||||
### Pour OAuth 2.0 :
|
||||
1. Créez `.env` avec `APP_URL=http://localhost:2222`
|
||||
2. Configurez OAuth 2.0 dans Google Cloud Console
|
||||
3. Dans NoteFlow : Administration > Google Calendar > OAuth 2.0
|
||||
4. Ajoutez Client ID et Client Secret
|
||||
5. Cliquez sur "Se connecter avec Google"
|
||||
|
||||
### Pour Service Account :
|
||||
1. Créez un Service Account sur Google Cloud Console
|
||||
2. Téléchargez la clé JSON
|
||||
3. Partagez votre calendrier avec l'email du Service Account
|
||||
4. Dans NoteFlow : Administration > Google Calendar > Service Account
|
||||
5. Collez le JSON et l'email du calendrier
|
||||
6. Cliquez sur "Synchroniser"
|
||||
|
||||
---
|
||||
|
||||
## Documentation complète
|
||||
|
||||
📚 Consultez [OAUTH_SETUP.md](./OAUTH_SETUP.md) pour :
|
||||
- Guide pas à pas complet
|
||||
- Résolution des erreurs
|
||||
- Checklist de vérification
|
||||
- Conseils de dépannage
|
||||
+103
-17
@@ -12,6 +12,22 @@ router.use(authenticateToken);
|
||||
// Scopes Google Calendar requis
|
||||
const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly'];
|
||||
|
||||
/**
|
||||
* Types d'authentification supportés
|
||||
*/
|
||||
const AUTH_TYPES = {
|
||||
OAUTH2: 'oauth2',
|
||||
SERVICE_ACCOUNT: 'service_account'
|
||||
};
|
||||
|
||||
/**
|
||||
* Récupérer le type d'authentification configuré
|
||||
*/
|
||||
async function getAuthType() {
|
||||
const authType = await getOne("SELECT value FROM settings WHERE key = 'google_auth_type'");
|
||||
return authType?.value || AUTH_TYPES.OAUTH2; // Par défaut OAuth2
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer un client OAuth2
|
||||
* @param {string} [customRedirectUri] - URI de redirection personnalisée (optionnel)
|
||||
@@ -35,6 +51,51 @@ async function getOAuth2Client(customRedirectUri = null) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer un client avec Service Account
|
||||
*/
|
||||
async function getServiceAccountClient() {
|
||||
const serviceAccountKey = await getOne("SELECT value FROM settings WHERE key = 'google_service_account_key'");
|
||||
|
||||
if (!serviceAccountKey || !serviceAccountKey.value) {
|
||||
throw new Error('Clé Service Account non configurée');
|
||||
}
|
||||
|
||||
try {
|
||||
const credentials = JSON.parse(serviceAccountKey.value);
|
||||
|
||||
const auth = new google.auth.GoogleAuth({
|
||||
credentials,
|
||||
scopes: SCOPES
|
||||
});
|
||||
|
||||
return await auth.getClient();
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors de la création du client Service Account:', error);
|
||||
throw new Error('Clé Service Account invalide');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer un client Google Calendar selon la méthode d'authentification
|
||||
* @param {number} userId - ID de l'utilisateur (pour OAuth2)
|
||||
*/
|
||||
async function getCalendarClient(userId = null) {
|
||||
const authType = await getAuthType();
|
||||
|
||||
if (authType === AUTH_TYPES.SERVICE_ACCOUNT) {
|
||||
const auth = await getServiceAccountClient();
|
||||
return google.calendar({ version: 'v3', auth });
|
||||
} else {
|
||||
// OAuth2
|
||||
if (!userId) {
|
||||
throw new Error('User ID requis pour OAuth2');
|
||||
}
|
||||
const oauth2Client = await getValidTokens(userId);
|
||||
return google.calendar({ version: 'v3', auth: oauth2Client });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/calendar/auth-url
|
||||
* Générer l'URL d'authentification OAuth
|
||||
@@ -153,19 +214,36 @@ router.get('/oauth-callback', async (req, res) => {
|
||||
*/
|
||||
router.get('/auth-status', async (req, res) => {
|
||||
try {
|
||||
const tokens = await getOne(
|
||||
'SELECT access_token, expiry_date FROM google_oauth_tokens WHERE user_id = ?',
|
||||
[req.user.id]
|
||||
);
|
||||
const authType = await getAuthType();
|
||||
|
||||
const isAuthenticated = !!tokens;
|
||||
const isExpired = tokens && tokens.expiry_date && tokens.expiry_date < Date.now();
|
||||
if (authType === AUTH_TYPES.SERVICE_ACCOUNT) {
|
||||
// Vérifier si la clé Service Account est configurée
|
||||
const serviceAccountKey = await getOne("SELECT value FROM settings WHERE key = 'google_service_account_key'");
|
||||
const isAuthenticated = !!serviceAccountKey?.value;
|
||||
|
||||
res.json({
|
||||
isAuthenticated,
|
||||
isExpired,
|
||||
needsReauth: !isAuthenticated || isExpired
|
||||
});
|
||||
res.json({
|
||||
authType: AUTH_TYPES.SERVICE_ACCOUNT,
|
||||
isAuthenticated,
|
||||
isExpired: false,
|
||||
needsReauth: !isAuthenticated
|
||||
});
|
||||
} else {
|
||||
// OAuth2
|
||||
const tokens = await getOne(
|
||||
'SELECT access_token, expiry_date FROM google_oauth_tokens WHERE user_id = ?',
|
||||
[req.user.id]
|
||||
);
|
||||
|
||||
const isAuthenticated = !!tokens;
|
||||
const isExpired = tokens && tokens.expiry_date && tokens.expiry_date < Date.now();
|
||||
|
||||
res.json({
|
||||
authType: AUTH_TYPES.OAUTH2,
|
||||
isAuthenticated,
|
||||
isExpired,
|
||||
needsReauth: !isAuthenticated || isExpired
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Erreur lors de la vérification du statut OAuth:', error);
|
||||
res.status(500).json({ error: 'Erreur serveur' });
|
||||
@@ -246,15 +324,23 @@ router.get('/events', async (req, res) => {
|
||||
|
||||
/**
|
||||
* POST /api/calendar/sync
|
||||
* Synchroniser avec Google Calendar via OAuth
|
||||
* Synchroniser avec Google Calendar (OAuth2 ou Service Account)
|
||||
*/
|
||||
router.post('/sync', async (req, res) => {
|
||||
try {
|
||||
// Obtenir un client OAuth valide
|
||||
const oauth2Client = await getValidTokens(req.user.id);
|
||||
const authType = await getAuthType();
|
||||
let calendarId = 'primary'; // Par défaut : calendrier principal
|
||||
|
||||
// Créer un client Google Calendar avec OAuth
|
||||
const calendar = google.calendar({ version: 'v3', auth: oauth2Client });
|
||||
// Si Service Account, permettre de spécifier l'email du calendrier
|
||||
if (authType === AUTH_TYPES.SERVICE_ACCOUNT) {
|
||||
const calendarEmail = await getOne("SELECT value FROM settings WHERE key = 'google_calendar_email'");
|
||||
if (calendarEmail?.value) {
|
||||
calendarId = calendarEmail.value;
|
||||
}
|
||||
}
|
||||
|
||||
// Créer un client Google Calendar selon la méthode d'authentification
|
||||
const calendar = await getCalendarClient(req.user.id);
|
||||
|
||||
// Récupérer les événements des 30 prochains jours
|
||||
const now = new Date();
|
||||
@@ -262,7 +348,7 @@ router.post('/sync', async (req, res) => {
|
||||
futureDate.setDate(futureDate.getDate() + 30);
|
||||
|
||||
const response = await calendar.events.list({
|
||||
calendarId: 'primary', // Calendrier principal de l'utilisateur
|
||||
calendarId, // Utilise le calendrier configuré
|
||||
timeMin: now.toISOString(),
|
||||
timeMax: futureDate.toISOString(),
|
||||
maxResults: 50,
|
||||
|
||||
+124
-44
@@ -1345,52 +1345,129 @@ const Index = () => {
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<CalendarIcon className="h-5 w-5" />
|
||||
Configuration Google Calendar OAuth 2.0
|
||||
Configuration Google Calendar
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{/* Choix du type d'authentification */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="google-client-id">Client ID Google</Label>
|
||||
<Input
|
||||
id="google-client-id"
|
||||
type="text"
|
||||
placeholder="123456789-abcdef.apps.googleusercontent.com"
|
||||
value={settings.google_client_id || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_client_id: e.target.value })}
|
||||
/>
|
||||
<Label htmlFor="google-auth-type">Méthode d'authentification</Label>
|
||||
<Select
|
||||
value={settings.google_auth_type || 'oauth2'}
|
||||
onValueChange={(value) => setSettings({ ...settings, google_auth_type: value })}
|
||||
>
|
||||
<SelectTrigger id="google-auth-type">
|
||||
<SelectValue placeholder="Sélectionnez une méthode" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="oauth2">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">OAuth 2.0</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Calendrier personnel avec consentement utilisateur
|
||||
</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="service_account">
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">Service Account</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
Clé JSON pour calendriers partagés (sans interaction)
|
||||
</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
<strong>OAuth 2.0</strong> : Pour accéder au calendrier personnel avec autorisation de l'utilisateur.<br/>
|
||||
<strong>Service Account</strong> : Pour accéder à des calendriers partagés sans interaction utilisateur.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="google-client-secret">Client Secret Google</Label>
|
||||
<Input
|
||||
id="google-client-secret"
|
||||
type="password"
|
||||
placeholder="GOCSPX-..."
|
||||
value={settings.google_client_secret || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_client_secret: e.target.value })}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Créez un projet OAuth 2.0 sur{' '}
|
||||
<a href="https://console.cloud.google.com/apis/credentials" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">
|
||||
Google Cloud Console
|
||||
</a>
|
||||
{' '}et activez l'API Google Calendar.
|
||||
</p>
|
||||
<div className="p-3 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
||||
<p className="text-sm font-semibold text-yellow-900 dark:text-yellow-200 mb-1">
|
||||
⚠️ IMPORTANT : URI de redirection autorisée
|
||||
</p>
|
||||
<p className="text-xs text-yellow-800 dark:text-yellow-300 mb-2">
|
||||
Ajoutez cette URL exacte dans la console Google Cloud (OAuth 2.0 Client IDs → URIs de redirection autorisées) :
|
||||
</p>
|
||||
<code className="block p-2 bg-white dark:bg-gray-800 border border-yellow-300 dark:border-yellow-700 rounded text-xs font-mono break-all">
|
||||
{window.location.origin}/api/calendar/oauth-callback
|
||||
</code>
|
||||
<p className="text-xs text-yellow-800 dark:text-yellow-300 mt-2">
|
||||
💡 Si vous utilisez un domaine différent, créez un fichier .env avec APP_URL=https://votre-domaine.com
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* Configuration OAuth2 */}
|
||||
{(!settings.google_auth_type || settings.google_auth_type === 'oauth2') && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="google-client-id">Client ID Google</Label>
|
||||
<Input
|
||||
id="google-client-id"
|
||||
type="text"
|
||||
placeholder="123456789-abcdef.apps.googleusercontent.com"
|
||||
value={settings.google_client_id || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_client_id: e.target.value })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="google-client-secret">Client Secret Google</Label>
|
||||
<Input
|
||||
id="google-client-secret"
|
||||
type="password"
|
||||
placeholder="GOCSPX-..."
|
||||
value={settings.google_client_secret || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_client_secret: e.target.value })}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Créez un projet OAuth 2.0 sur{' '}
|
||||
<a href="https://console.cloud.google.com/apis/credentials" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">
|
||||
Google Cloud Console
|
||||
</a>
|
||||
{' '}et activez l'API Google Calendar.
|
||||
</p>
|
||||
<div className="p-3 bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg">
|
||||
<p className="text-sm font-semibold text-yellow-900 dark:text-yellow-200 mb-1">
|
||||
⚠️ IMPORTANT : URI de redirection autorisée
|
||||
</p>
|
||||
<p className="text-xs text-yellow-800 dark:text-yellow-300 mb-2">
|
||||
Ajoutez cette URL exacte dans la console Google Cloud (OAuth 2.0 Client IDs → URIs de redirection autorisées) :
|
||||
</p>
|
||||
<code className="block p-2 bg-white dark:bg-gray-800 border border-yellow-300 dark:border-yellow-700 rounded text-xs font-mono break-all">
|
||||
{window.location.origin}/api/calendar/oauth-callback
|
||||
</code>
|
||||
<p className="text-xs text-yellow-800 dark:text-yellow-300 mt-2">
|
||||
💡 Si vous utilisez un domaine différent, créez un fichier .env avec APP_URL=https://votre-domaine.com
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Configuration Service Account */}
|
||||
{settings.google_auth_type === 'service_account' && (
|
||||
<>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="google-service-account-key">Clé Service Account (JSON)</Label>
|
||||
<textarea
|
||||
id="google-service-account-key"
|
||||
className="w-full min-h-[200px] p-3 text-xs font-mono border rounded-md"
|
||||
placeholder='Collez ici le contenu du fichier JSON de votre Service Account { "type": "service_account", "project_id": "...", "private_key_id": "...", ... }'
|
||||
value={settings.google_service_account_key || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_service_account_key: e.target.value })}
|
||||
/>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Créez un Service Account sur{' '}
|
||||
<a href="https://console.cloud.google.com/iam-admin/serviceaccounts" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">
|
||||
Google Cloud Console
|
||||
</a>
|
||||
{' '}et téléchargez la clé JSON.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="google-calendar-email">Email du calendrier à synchroniser</Label>
|
||||
<Input
|
||||
id="google-calendar-email"
|
||||
type="email"
|
||||
placeholder="votre-email@gmail.com"
|
||||
value={settings.google_calendar_email || ''}
|
||||
onChange={(e) => setSettings({ ...settings, google_calendar_email: e.target.value })}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
⚠️ Important : Vous devez partager votre calendrier avec l'email du Service Account (visible dans le JSON)
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={handleSaveSettings} className="flex items-center gap-2">
|
||||
@@ -1399,14 +1476,17 @@ const Index = () => {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{settings.google_client_id && settings.google_client_secret && (
|
||||
{(
|
||||
((!settings.google_auth_type || settings.google_auth_type === 'oauth2') && settings.google_client_id && settings.google_client_secret) ||
|
||||
(settings.google_auth_type === 'service_account' && settings.google_service_account_key)
|
||||
) && (
|
||||
<>
|
||||
<div className="border-t pt-4">
|
||||
<h3 className="font-semibold mb-2">Statut de connexion</h3>
|
||||
{calendarAuthStatus.isAuthenticated && !calendarAuthStatus.isExpired ? (
|
||||
<div className="flex items-center gap-2 text-green-600">
|
||||
<div className="h-2 w-2 rounded-full bg-green-600"></div>
|
||||
<span>Connecté à Google Calendar</span>
|
||||
<span>Connecté à Google Calendar ({calendarAuthStatus.authType === 'service_account' ? 'Service Account' : 'OAuth 2.0'})</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 text-yellow-600">
|
||||
@@ -1417,12 +1497,12 @@ const Index = () => {
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
{calendarAuthStatus.needsReauth ? (
|
||||
{calendarAuthStatus.needsReauth && (!settings.google_auth_type || settings.google_auth_type === 'oauth2') ? (
|
||||
<Button onClick={handleGoogleConnect} className="flex items-center gap-2">
|
||||
<CalendarIcon className="h-4 w-4" />
|
||||
Se connecter avec Google
|
||||
</Button>
|
||||
) : (
|
||||
) : !calendarAuthStatus.needsReauth && (!settings.google_auth_type || settings.google_auth_type === 'oauth2') ? (
|
||||
<>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
|
||||
Reference in new issue
Block a user