true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'], CURLOPT_POSTFIELDS => http_build_query($fields), CURLOPT_TIMEOUT => 30, ]); $res = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($res === false) { throw new Exception('cURL error: ' . curl_error($ch)); } curl_close($ch); return [$code, $res]; } function http_get_auth($url, $bearer) { $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $bearer], CURLOPT_TIMEOUT => 30, ]); $res = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if ($res === false) { throw new Exception('cURL error: ' . curl_error($ch)); } curl_close($ch); return [$code, $res]; } // ---- 1) Charger la clé de service ---- if (!file_exists($jsonPath)) die("Fichier JSON introuvable: $jsonPath\n"); $creds = json_decode(file_get_contents($jsonPath), true); if (!$creds) die("Impossible de parser le JSON\n"); $client_email = $creds['client_email']; $private_key = $creds['private_key']; $token_uri = isset($creds['token_uri']) ? $creds['token_uri'] : 'https://oauth2.googleapis.com/token'; // ---- 2) Construire le JWT (RS256) ---- // Scopes minimum lecture/écriture d’événements: $scope = 'https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.events'; $now = time(); $exp = $now + 3600; // 1h $iss = $client_email; $sub = $impersonate; // <- impersonation (DWD) $aud = $token_uri; $header = ['alg' => 'RS256', 'typ' => 'JWT']; $claim = [ 'iss' => $iss, 'scope' => $scope, 'aud' => $aud, 'exp' => $exp, 'iat' => $now, 'sub' => $sub ]; $jwt_unsigned = b64url(json_encode($header)) . '.' . b64url(json_encode($claim)); // Signer avec la clé privée $signature = ''; $ok = openssl_sign($jwt_unsigned, $signature, $private_key, 'sha256WithRSAEncryption'); if (!$ok) { die("Échec openssl_sign(). Vérifie la private_key.\n"); } $jwt = $jwt_unsigned . '.' . b64url($signature); // ---- 3) Échanger le JWT contre un access_token ---- list($code, $body) = http_post_json($token_uri, [ 'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt ]); if ($code !== 200) { echo "Échec token ($code): $body\n"; exit(1); } $tok = json_decode($body, true); $access_token = $tok['access_token'] ?? null; if (!$access_token) { die("Pas d'access_token dans la réponse.\n"); } echo "OK token reçu.\n"; // ---- 4) Appel test non destructif : lister les agendas de l'utilisateur ---- $url = 'https://www.googleapis.com/calendar/v3/users/me/calendarList'; list($code2, $body2) = http_get_auth($url, $access_token); echo "GET calendarList => HTTP $code2\n"; echo $body2 . "\n"; // ---- 5) Créer un petit événement de test (dans primary) ---- $event = [ 'summary' => 'Test CRM↔Google', 'description' => 'Évènement de validation DWD', 'start' => ['dateTime' => date('c', time()+3600)], // +1h 'end' => ['dateTime' => date('c', time()+7200)], // +2h ]; $ch = curl_init('https://www.googleapis.com/calendar/v3/calendars/primary/events'); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ 'Authorization: Bearer '.$access_token, 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => json_encode($event), CURLOPT_TIMEOUT => 30, ]); $resp = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); echo "POST event => HTTP $code\n$resp\n";