tokens --- $post = [ 'grant_type' => 'authorization_code', 'code' => $code, 'redirect_uri' => $OIDC_REDIRECT_URI, 'client_id' => $OIDC_CLIENT_ID, 'code_verifier' => $codeVerifier, ]; if ($OIDC_CLIENT_SECRET !== '') { $post['client_secret'] = $OIDC_CLIENT_SECRET; } $ch = curl_init($tokenEndpoint); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($post, '', '&', PHP_QUERY_RFC3986), CURLOPT_TIMEOUT => 15, ]); $tokenResponse = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); if ($tokenResponse === false || $httpCode !== 200) { http_response_code(500); echo $debug ? 'Échec échange token: ' . htmlspecialchars($err ?: (string)$tokenResponse) : 'Erreur d’authentification.'; exit; } $tokens = json_decode((string)$tokenResponse, true) ?: []; $accessToken = $tokens['access_token'] ?? null; $idToken = $tokens['id_token'] ?? null; if (!$accessToken) { http_response_code(500); echo $debug ? 'Access token manquant.' : 'Erreur d’authentification.'; exit; } // --- UserInfo --- $ch = curl_init($userInfoEndpoint); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $accessToken], CURLOPT_TIMEOUT => 10, ]); $userInfoResponse = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($userInfoResponse === false || $httpCode !== 200) { http_response_code(500); echo $debug ? 'Échec UserInfo: ' . htmlspecialchars((string)$userInfoResponse) : 'Erreur d’authentification.'; exit; } $claims = json_decode((string)$userInfoResponse, true) ?: []; // --- Récup info utiles --- $email = $claims['email'] ?? null; $username = $claims['preferred_username'] ?? ($email ?: null); $firstname = $claims['given_name'] ?? null; $lastname = $claims['family_name'] ?? null; if (!$email && $idToken && substr_count($idToken, '.') === 2) { [, $p, ] = explode('.', $idToken, 3); $payloadJson = base64_decode(strtr($p, '-_', '+/'), true); $payload = $payloadJson ? json_decode($payloadJson, true) : null; if (is_array($payload) && !empty($payload['email'])) { $email = $payload['email']; } } if (!$email) { http_response_code(400); echo $debug ? 'Email non fourni par IdP.' : 'Impossible de récupérer votre email.'; exit; } // --- Si l'utilisateur existe déjà -> connecter et redirect --- $flow = $_SESSION['oidc_flow'] ?? 'login'; // Vérifie existence en base /** @var \PDO $pdo */ $pdo = Database::get(); $stmt = $pdo->prepare('SELECT id FROM users WHERE email = :email LIMIT 1'); $stmt->execute([':email' => $email]); $existingId = $stmt->fetchColumn(); // Si flow=login ET utilisateur existe → connexion directe if ($flow === 'login' && $existingId) { $_SESSION['user_id'] = (int)$existingId; $_SESSION['user_email'] = $email; $_SESSION['oidc'] = [ 'issuer' => $OIDC_ISSUER, 'sub' => $claims['sub'] ?? null, 'access_token' => $accessToken, 'id_token' => $idToken, 'expires_at' => time() + (int)($tokens['expires_in'] ?? 3600), ]; $target = $_SESSION['oidc_return_to'] ?? '/'; unset($_SESSION['oidc_return_to'], $_SESSION['oidc_flow']); if (!is_string($target) || $target === '' || $target[0] !== '/') { $target = '/'; } header('Location: ' . $target, true, 303); exit; } // Sinon : go formulaire d’inscription (pré-rempli) $_SESSION['pending_oidc'] = [ 'issuer' => $OIDC_ISSUER, 'sub' => $claims['sub'] ?? null, 'email' => $email, 'username' => $claims['preferred_username'] ?? ($email ?: null), 'firstname' => $claims['given_name'] ?? null, 'lastname' => $claims['family_name'] ?? null, ]; unset($_SESSION['oidc_flow']); header('Location: ' . url('register/from-oidc'), true, 303); exit;