context->link->getAdminLink( 'AdminModules', // Target Admin Controller true, // Generate a security token [], // No specific route needed ['configure' => $this->module->name] // Add 'configure' parameter ); // If Mautic returned an error (e.g., user denied access) if ($error) { // Use a cookie to pass the error message to the back office. $this->context->cookie->mautic_error = $this->trans('Mautic authorization failed: %s', [$error], 'Modules.Mauticconnect.Admin'); // Redirect back to the config page with an error flag. Tools::redirect($adminModuleLink . '&auth_error=1'); } // If Mautic did not return an authorization code, which is required. if (!$code) { $this->context->cookie->mautic_error = $this->trans('Invalid response from Mautic: No authorization code received.', [], 'Modules.Mauticconnect.Admin'); Tools::redirect($adminModuleLink . '&auth_error=1'); } // If we have a code, proceed to exchange it for an access token. $this->exchangeCodeForToken($code, $adminModuleLink); } /** * Exchanges the authorization code for an access token by making a POST request to Mautic. * * @param string $code The authorization code from Mautic. * @param string $redirectUrl The admin URL to redirect to after processing. */ protected function exchangeCodeForToken($code, $redirectUrl) { $mauticUrl = Configuration::get(MauticConnect::MAUTIC_URL); $tokenUrl = $mauticUrl . '/oauth/v2/token'; $postData = [ 'client_id' => Configuration::get(MauticConnect::MAUTIC_CLIENT_ID), 'client_secret' => Configuration::get(MauticConnect::MAUTIC_CLIENT_SECRET), 'grant_type' => 'authorization_code', 'redirect_uri' => $this->context->link->getModuleLink($this->module->name, 'oauth2', [], true), 'code' => $code, ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $tokenUrl); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postData)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { $this->context->cookie->mautic_error = $this->trans('cURL Error while contacting Mautic: %s', [$curlError], 'Modules.Mauticconnect.Admin'); Tools::redirect($redirectUrl . '&auth_error=1'); } $data = json_decode($response, true); if ($httpCode !== 200 || !isset($data['access_token'])) { $errorMessage = isset($data['error_description']) ? $data['error_description'] : $response; $this->context->cookie->mautic_error = $this->trans('Failed to get access token. Mautic responded with: %s', [$errorMessage], 'Modules.Mauticconnect.Admin'); Tools::redirect($redirectUrl . '&auth_error=1'); } // --- Success! Save the tokens --- Configuration::updateValue(MauticConnect::MAUTIC_ACCESS_TOKEN, $data['access_token']); Configuration::updateValue(MauticConnect::MAUTIC_REFRESH_TOKEN, $data['refresh_token']); $expiresIn = isset($data['expires_in']) ? (int)$data['expires_in'] : 3600; $expiresAt = time() + $expiresIn - 60; // Subtract 60s buffer Configuration::updateValue(MauticConnect::MAUTIC_TOKEN_EXPIRES, $expiresAt); // Redirect back to the module configuration page with a success flag Tools::redirect($redirectUrl . '&auth_success=1'); } }