Gmail API get list "An error occurred: { "error": "invalid_grant", "error_description": "Bad Request" } " in PHP - api

I am trying to get mail list using php library. It was working before , but now it show the following error :
An error occurred: { "error": "invalid_grant", "error_description":
"Bad Request" }
array(0) { }
Code:
function getList($lastsynctime='') {
// Get the API client and construct the service object.
$client = $this->getClient();
$service = new Google_Service_Gmail($client);
// $newTime = strtotime('-15 minutes');
if ($lastsynctime =='') {
$newTime = strtotime('-60 day');
$after = strtotime(date('Y-m-d H:i:s', $newTime));
}else{
$after = strtotime($lastsynctime);
}
// Print the labels in the user's account.
$userId = 'me';
$pageToken = NULL;
$messages = array();
$opt_param = array();
do {
try {
if ($pageToken) {
$opt_param['pageToken'] = $pageToken;
}
$opt_param['q'] = "from:example#gmail.com after:$after";
$messagesResponse = $service->users_messages->listUsersMessages($userId, $opt_param);
echo "<pre>";var_dump($messagesResponse);
} catch (Exception $e) {
print 'An error occurred: ' . $e->getMessage();
}
} while ($pageToken);
return $messagesResponse;
}

Well! As your code was working before and you haven't change anything. Then i think the problem is not in you code.
You can check your Connected apps and sites settings under your gmail My Account menu to make sure your app is there.
If the app is there but yet not working then you need to delete the app and regenerate your client secret key. Because your client secret may get expired.

I got this error in different API (Google Search Console).
Try visiting https://myaccount.google.com/security#connectedapps from your Gmail account.
See if Drive Testing Key shows up under Apps with account access. If it doesn't, then as #Mahbubul Islam mentioned, you'll need to create the credentials again.

Related

Facebook api returns : (#120) Invalid album id when trying to post to a group

When I try to post a photo in a group through the API I get an error, the post happens, but without the photo.
I've seen people say it's a bug on Facebook and it happens when there's a question mark (?).
However in my post there is no question mark, does anyone know what it could be?
The error i get is: (#120) Invalid album id
Example:
I am using Facebook SDK for PHP like this, and i have a custom method, like this.
public function postPhoto(string $message, string $img_path, string $page, string $id='me')
{
$photoData = [
'message' => $message,
'source' => $this->fb->fileToUpload($img_path),
];
$this->pageAccessToken = $this->getTokenForPage($page);
try {
$response = $this->fb->post("/$id/photos", $photoData, $this->pageAccessToken);
$graphNode = $response->getGraphNode();
$this->post_id = $graphNode['id'];
} catch (FacebookResponseException $e) {
$this->error = $e->getMessage();
return false;
} catch (FacebookSDKException $e) {
$this->error = $e->getMessage();
return false;
}
}

xero api failing to add tracking on purchase order

When I add tracking to invoices or credit notes via the api it works fine. but when i try to add it on purchase order it fails and I cannot seem to get a clear error message out of it.
I am using accounting api https://xeroapi.github.io/xero-php-oauth2/docs/v2/accounting/index.html#api-Accounting-updatePurchaseOrder
Error I get is message: "[400] Client error: POST https://api.xero.com/api.xro/2.0/PurchaseOrders/42797164-58c9-483c-9af8-96165c31a26f` resulted in a 400 Bad Request response:\n{\r\n "ErrorNumber": 10,\r\n "Type": "ValidationException",\r\n "Message": "A validation exception occurred",\r\n "Elements" (truncated...)\n"
`
Code I am using to try set it after I have created the purchase order.
[$trackingCategoryId, $trackingOptionId] = $this->getTrackingCategoryByNameFromXero($projectName, 'Project');
$purchaseOrder = null;
$xeroTenantId = $this->xero_account->tenantId;
try {
$purchaseOrders = $this->accountingApi->getPurchaseOrder($xeroTenantId, $purchaseOrderId);
foreach ($purchaseOrders as $model) {
if ($model->getPurchaseOrderId() == $purchaseOrderId) {
$purchaseOrder = $model;
break;
}
}
} catch (Exception $e) {
echo 'Exception when calling AccountingApi->getPurchaseOrder: ', $e->getMessage(), PHP_EOL;
}
if ($purchaseOrder instanceof PurchaseOrder) {
$lineItems = $purchaseOrder->getLineItems();
foreach ($lineItems as $lineItem) {
$tc = new LineItemTracking();
$tc->setTrackingCategoryId($trackingCategoryId);
$tc->setTrackingOptionId($trackingOptionId);
$lineItem->setTracking([$tc]);
$lineItems[] = $lineItem;
}
$purchaseOrder->setLineItems($lineItems);
$purchaseOrders = new PurchaseOrders();
$arr_purchase_orders[] = $purchaseOrder;
$purchaseOrders->setPurchaseOrders($arr_purchase_orders);
$summarizeErrors = true;
try {
$x = $this->accountingApi->updatePurchaseOrder(
$this->xero_account->tenantId,
$purchaseOrderId,
$purchaseOrders
);
} catch (\ApiException $e) {
print_r($e->getMessage());die;
}
}

How to implement code for OAuth 2.0 Authorization for Google Directory API Without Command Line Interface

I have seen code in google directory api documentation for command line interface and have worked with it, the code works fine. But I want write code that runs without terminal and runs when on a page when the page is loaded because i have to run the code in the terminal every hour after it's expired, is there anyway i can get the code to run when i visit the page of authorization code.
The code work's with command-line interface, but i want it to work without command-line, what can i do?
Given Below is the code from Google Directory API and the URL:
URL : https://developers.google.com/admin-sdk/directory/v1/quickstart/php
<?php
require __DIR__ . '/vendor/autoload.php';
if (php_sapi_name() != 'cli') {
throw new Exception('This application must be run on the command line.');
}
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('G Suite Directory API PHP Quickstart');
$client->setScopes(Google_Service_Directory::ADMIN_DIRECTORY_USER_READONLY);
$client->setAuthConfig('credentials.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
// Load previously authorized token from a file, if it exists.
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
$tokenPath = 'token.json';
if (file_exists($tokenPath)) {
$accessToken = json_decode(file_get_contents($tokenPath), true);
$client->setAccessToken($accessToken);
}
// If there is no previous token or it's expired.
if ($client->isAccessTokenExpired()) {
// Refresh the token if possible, else fetch a new one.
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
} else {
// Request authorization from the user.
$authUrl = $client->createAuthUrl();
printf("Open the following link in your browser:\n%s\n", $authUrl);
print 'Enter verification code: ';
$authCode = trim(fgets(STDIN));
// Exchange authorization code for an access token.
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
$client->setAccessToken($accessToken);
// Check to see if there was an error.
if (array_key_exists('error', $accessToken)) {
throw new Exception(join(', ', $accessToken));
}
}
// Save the token to a file.
if (!file_exists(dirname($tokenPath))) {
mkdir(dirname($tokenPath), 0700, true);
}
file_put_contents($tokenPath, json_encode($client->getAccessToken()));
}
return $client;
}
// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Directory($client);
// Print the first 10 users in the domain.
$optParams = array(
'customer' => 'my_customer',
'maxResults' => 10,
'orderBy' => 'email',
);
$results = $service->users->listUsers($optParams);
if (count($results->getUsers()) == 0) {
print "No users found.\n";
} else {
print "Users:\n";
foreach ($results->getUsers() as $user) {
printf("%s (%s)\n", $user->getPrimaryEmail(),
$user->getName()->getFullName());
}
}
I have also tried to implement the code from OAuth 2.0 for Web Server Applications in wordpress page with the template but it's not working, which is from https://developers.google.com/identity/protocols/oauth2/web-server#php_1
and this is my code:
<?php
require __DIR__ . '/vendor/autoload.php';
session_start();
/**
* Returns an authorized API client.
* #return Google_Client the authorized client object
*/
$client = new Google_Client();
$client->setApplicationName('G Suite Directory API PHP Quickstart');
$client->addScope(Google_Service_Directory::ADMIN_DIRECTORY_USER);
$client->setAuthConfig('/path/to/credentials.json');
$client->setAccessType('offline');
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true); // incremental auth
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$service = new Google_Service_Directory($client);
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

How to fix this service account creation error?

I am creating service account programmatically for project using java sbt play framework using google java sdk
code sample
but I'm getting this error response
com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
"code" : 403,
"errors" : [ {
"domain" : "global",
"message" : "Permission iam.serviceAccountKeys.create is required to perform this operation on service account projects/from-gcloud-249112/serviceAccounts/bhavaay-anand-095#from-gcloud-249112.iam.gserviceaccount.com.",
"reason" : "forbidden"
} ],
"message" : "Permission iam.serviceAccountKeys.create is required to perform this operation on service account projects/from-gcloud-249112/serviceAccounts/bhavaay-anand-095#from-gcloud-249112.iam.gserviceaccount.com.",
"status" : "PERMISSION_DENIED"
}
What I'm doing wrong? I'm using exact code from google code sample.
public ServiceAccount createServiceAccount(String projectId, String name, String displayName) throws IOException {
GoogleCredential credential = GoogleCredential.getApplicationDefault();
if (credential.createScopedRequired()) {
credential =
credential.createScoped(Arrays.asList("https://www.googleapis.com/auth/cloud-platform"));
}
try {
final Iam service = new Iam.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
JacksonFactory.getDefaultInstance(),
credential)
.setApplicationName("service-accounts")
.build();
ServiceAccount serviceAccount = new ServiceAccount();
serviceAccount.setDisplayName(displayName);
CreateServiceAccountRequest request = new CreateServiceAccountRequest();
request.setAccountId(name);
request.setServiceAccount(serviceAccount);
String serviceAccountEmail = "xxx";
ServiceAccountKey key =
service
.projects()
.serviceAccounts()
.keys()
.create(
"projects/" + projectId +"/serviceAccounts/" + serviceAccountEmail,
new CreateServiceAccountKeyRequest())
.execute();
System.out.println("Created service account: " + serviceAccount);
return serviceAccount;
} catch(GeneralSecurityException e){
System.err.println(e.getMessage());
return null;
}
}
The error is that you are missing the permission "iam.serviceAccountKeys.create" to perform that command.
i see that you are loading the default credentials:
GoogleCredential credential = GoogleCredential.getApplicationDefault();
But did you set the proper credentials before?
Try doing
gcloud auth login
or
export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
See more information about it HERE.

Got problems with webhook to Telegram Bot API

Why is my webhook not working? I do not get any data from telegram bot API. Here is the detailed explanation of my problem:
I got SSL cert from StartSSL, it works fine on my website (according to GeoCerts SSL checker), but still seems like my webhook to Telegram Bot API doesn't work (despite it says that webhook was set I do not get any data).
I am making a webhook to my script on my website in this form:
https://api.telegram.org/bot<token>/setWebhook?url=https://mywebsite.com/path/to/giveawaysbot.php
I get this text in response:
{"ok":true,"result":true,"description":"Webhook was set"}
So it must be working, but it actually doesn't.
Here is my script code:
<?php
ini_set('error_reporting', E_ALL);
$botToken = "<token>";
$website = "https://api.telegram.org/bot".$botToken;
$update = file_get_contents('php://input');
$update = json_decode($update);
print_r($update); // this is made to check if i get any data or not
$chatId = $update["message"]["chat"]["id"];
$message = $update["message"]["text"];
switch ($message) {
case "/test":
sendMessage($chatId,"test complete");
break;
case "/hi":
sendMessage($chatId,"hey there");
break;
default:
sendMessage($chatId,"nono i dont understand you");
}
function sendMessage ($chatId, $message) {
$url = $GLOBALS[website]."/sendMessage?chat_id=".$chatId."&text=".urlencode($message);
file_get_contents($url);
}
?>
I don't actually receive any data to $update. So webhook is not working. Why?
Just another one moment, why your webhooks not work.
In my case the reason was in allowed_updates webhook parameter.
By calling :
https://api.telegram.org/bot<your_bot_token>/getWebhookInfo
You can see
{
"ok": true,
"result": {
"url": "<your webhook url should be here>",
"has_custom_certificate": false,
"pending_update_count": 0,
"max_connections": 40,
"allowed_updates": [
"callback_query"
]
}
}
It means, that your bot can't react to your text messages, and you will not receive any webhooks!
You can note, that "allowed_updates" contains array. So, currently it will react only to inline button events (passed as keyboard layout!). According to the setWebhook documentation, allowed_updates is an "optional" parameter.
To start receieve text messages, you need to add "message" to your "allowed_updates" prop. To do it, just again set your webhooks and add it to query. Like here :
https://api.telegram.org/bot<your_token>/setWebHook?url=<your_url>&allowed_updates=["callback_query","message"]
You will receive something like "url already added", but don't worry, allowed_updates will be updated even in this case. Just try type your message to bot and test your webhooks.
That's all, now, telegram will send webhooks to each direct message from you to your bot. Hope, it helps someone.
I was with this problem. I was trying to look everywhere and couldn't find the solution for my problem, because people were all the time saying that the problem was the SSL certificate. But I found the problem, and that were a lot of things missing on the code to interact with the telegram API webhook envolving curl and this kind of stuff. After I looked in an example at the telegram bot documentation, I solved my problem. Look this example https://core.telegram.org/bots/samples/hellobot
<?php
//telegram example
define('BOT_TOKEN', '12345678:replace-me-with-real-token');
define('API_URL', 'https://api.telegram.org/bot'.BOT_TOKEN.'/');
function apiRequestWebhook($method, $parameters) {
if (!is_string($method)) {
error_log("Method name must be a string\n");
return false;
}
if (!$parameters) {
$parameters = array();
} else if (!is_array($parameters)) {
error_log("Parameters must be an array\n");
return false;
}
$parameters["method"] = $method;
header("Content-Type: application/json");
echo json_encode($parameters);
return true;
}
function exec_curl_request($handle) {
$response = curl_exec($handle);
if ($response === false) {
$errno = curl_errno($handle);
$error = curl_error($handle);
error_log("Curl returned error $errno: $error\n");
curl_close($handle);
return false;
}
$http_code = intval(curl_getinfo($handle, CURLINFO_HTTP_CODE));
curl_close($handle);
if ($http_code >= 500) {
// do not wat to DDOS server if something goes wrong
sleep(10);
return false;
} else if ($http_code != 200) {
$response = json_decode($response, true);
error_log("Request has failed with error {$response['error_code']}: {$response['description']}\n");
if ($http_code == 401) {
throw new Exception('Invalid access token provided');
}
return false;
} else {
$response = json_decode($response, true);
if (isset($response['description'])) {
error_log("Request was successfull: {$response['description']}\n");
}
$response = $response['result'];
}
return $response;
}
function apiRequest($method, $parameters) {
if (!is_string($method)) {
error_log("Method name must be a string\n");
return false;
}
if (!$parameters) {
$parameters = array();
} else if (!is_array($parameters)) {
error_log("Parameters must be an array\n");
return false;
}
foreach ($parameters as $key => &$val) {
// encoding to JSON array parameters, for example reply_markup
if (!is_numeric($val) && !is_string($val)) {
$val = json_encode($val);
}
}
$url = API_URL.$method.'?'.http_build_query($parameters);
$handle = curl_init($url);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
return exec_curl_request($handle);
}
function apiRequestJson($method, $parameters) {
if (!is_string($method)) {
error_log("Method name must be a string\n");
return false;
}
if (!$parameters) {
$parameters = array();
} else if (!is_array($parameters)) {
error_log("Parameters must be an array\n");
return false;
}
$parameters["method"] = $method;
$handle = curl_init(API_URL);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($handle, CURLOPT_TIMEOUT, 60);
curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($parameters));
curl_setopt($handle, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
return exec_curl_request($handle);
}
function processMessage($message) {
// process incoming message
$message_id = $message['message_id'];
$chat_id = $message['chat']['id'];
if (isset($message['text'])) {
// incoming text message
$text = $message['text'];
if (strpos($text, "/start") === 0) {
apiRequestJson("sendMessage", array('chat_id' => $chat_id, "text" => 'Hello', 'reply_markup' => array(
'keyboard' => array(array('Hello', 'Hi')),
'one_time_keyboard' => true,
'resize_keyboard' => true)));
} else if ($text === "Hello" || $text === "Hi") {
apiRequest("sendMessage", array('chat_id' => $chat_id, "text" => 'Nice to meet you'));
} else if (strpos($text, "/stop") === 0) {
// stop now
} else {
apiRequestWebhook("sendMessage", array('chat_id' => $chat_id, "reply_to_message_id" => $message_id, "text" => 'Cool'));
}
} else {
apiRequest("sendMessage", array('chat_id' => $chat_id, "text" => 'I understand only text messages'));
}
}
define('WEBHOOK_URL', 'https://my-site.example.com/secret-path-for-webhooks/');
if (php_sapi_name() == 'cli') {
// if run from console, set or delete webhook
apiRequest('setWebhook', array('url' => isset($argv[1]) && $argv[1] == 'delete' ? '' : WEBHOOK_URL));
exit;
}
$content = file_get_contents("php://input");
$update = json_decode($content, true);
if (!$update) {
// receive wrong update, must not happen
exit;
}
if (isset($update["message"])) {
processMessage($update["message"]);
}
?>
I had similar problem. Now solved.
The problem is possibly in a wrong public certificate. Please follow with attention instructions I propose in my project:
https://github.com/solyaris/BOTServer/blob/master/wiki/usage.md#step-4-create-self-signed-certificate
openssl req -newkey rsa:2048 -sha256 -nodes -keyout /your_home/BOTServer/ssl/PRIVATE.key -x509 -days 365 -out /your_home/BOTServer/ssl/PUBLIC.pem -subj "/C=IT/ST=state/L=location/O=description/CN=your_domain.com"
Telegram setWebhooks API do not check data inside your self-signed digital certificate, returning "ok" even if by example you do not specify a valid /CN! So be carefull to generate a public .pem certificate containing /CN=your_domain corresponding to your REAL HOST domain name!
It may be the SSL cert. I had the same problem: Webhook confirmed but actually SSL cert borked.
This reddit thread was helpful: https://www.reddit.com/r/Telegram/comments/3b4z1k/bot_api_recieving_nothing_on_a_correctly/
This may help who works with Laravel Telegram SDK.
I had a problem with self-signed webhook in Laravel 5.3.
After setup and getting OK result from Telegram with "Webhook was set" message, it didn't work.
The problem was related to CSRF verification. So I added the webhook url to CSRF exceptions and now everything works like a charm.
I had this problem too, after somehow the telegram didn't run my bot, so I tried to renew the certificate and set web hooks again, but again it didn't work, so I updated my VPS(yum update) and then renew my certificate and set web hooks again. after these it started working again.
This is because you are not setting the certificate like this
curl -F "url=https://bot.sapamatech.com/tg" -F "certificate=#/etc/apache2/ssl/bot.pem" https://api.telegram.org/bot265033849:AAHAs6vKVlY7UyqWFUHoE7Toe2TsGvu0sf4/setWebhook
Check this link on how to set Telegram Self Signed Certificate
Try this code. If you have a valid SSL on your web host and you have properly run the setWebhook, it should work (does for me). Make sure you create a file called "log.txt" and give write permission to it:
<?php
define('BOT_TOKEN', '????');
define('API_URL', 'https://api.telegram.org/bot'.BOT_TOKEN.'/');
// read incoming info and grab the chatID
$content = file_get_contents("php://input");
$update = json_decode($content, true);
$chatID = $update["message"]["chat"]["id"];
$message = $update["message"]["text"];
// compose reply
$reply ="";
switch ($message) {
case "/start":
$reply = "Welcome to Siamaks's bot. Type /help to see commands";
break;
case "/test":
$reply = "test complete";
break;
case "/hi":
$reply = "hey there";
break;
case "/help":
$reply = "commands: /start , /test , /hi , /help ";
break;
default:
$reply = "NoNo, I don't understand you";
}
// send reply
$sendto =API_URL."sendmessage?chat_id=".$chatID."&text=".$reply;
file_get_contents($sendto);
// Create a debug log.txt to check the response/repy from Telegram in JSON format.
// You can disable it by commenting checkJSON.
checkJSON($chatID,$update);
function checkJSON($chatID,$update){
$myFile = "log.txt";
$updateArray = print_r($update,TRUE);
$fh = fopen($myFile, 'a') or die("can't open file");
fwrite($fh, $chatID ."nn");
fwrite($fh, $updateArray."nn");
fclose($fh);
}
I had this problem too. In my case was mistake in declaring my API method. I created GET method instead of POST at first.
#api.route('/my-webhook-url')
class TelegramWebhook(Resource):
def post(self): # POST, Carl!
# ...
return response
In my case the error was due to the PHP configuration ( using cPanel )
[26-Jan-2021 09:38:17 UTC] PHP Warning: file_get_contents(): https:// wrapper is disabled in the server configuration by allow_url_fopen=0 in /home/myUsername/public_html/mydomain.com/my_bot_file.php on line 40
and
[26-Jan-2021 09:38:17 UTC] PHP Warning: file_get_contents(https://api.telegram.org/bot<my-bot-id>/sendmessage?chat_id=647778451&text=hello charlie ! k99 ): failed to open stream: no suitable wrapper could be found in /home/myUsername/public_html/myDomain.com/my_bot_file.php on line 40
so - it is pretty self explanatory.
The allow_url_fopen=0 var in the php configuration actually disables the requiered action.
But anyhow your best bet is to look at the error log on your server and see if there are any other errors in the script or server config.