removing authentication when integrating google api to dialogflow webhook - php

I'm creating an AI Assistant using Dialogflow and I need to use Google APIs (google calendar and gmail). The APIs were working perfectly (I used this as reference). However, when I integrated my code with the dialogflow webhook, it returns Webhook Call failed. Error: 500 Internal Server Error.
here is a code snippet:
$client = new Google_Client();
$client->addScope(Google_Service_Gmail::GMAIL_READONLY); //view your emails and settings
$client->addScope(Google_Service_Gmail::GMAIL_COMPOSE); //manage drafts and send emails
$client->addScope(Google_Service_Gmail::GMAIL_MODIFY);
$client->addScope(Google_Service_Gmail::GMAIL_SEND); //send email on your behalf
$client->addScope(Google_Service_Calendar::CALENDAR); //manage calendar
$client->setAuthConfig('client_secret.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('auto');
if($_SERVER['REQUEST_METHOD'] == 'POST'){
if(isset($_SESSION['access_token']) && $_SESSION['access_token']){
$client->setAccessToken($_SESSION['access_token']);
$gmail = new Google_Service_Gmail($client);
$user = "emailaddress#gmail.com";
$calendar = new Google_Service_Calendar($client);
$intent = $json->queryResult->intent->displayName;
$location_any = $json->queryResult->parameters->location_any;
$text = $json->queryResult->parameters->text;
$name = $json->queryResult->parameters->name;
$choice = $json->queryResult->parameters->choice;
$subject = $json->queryResult->parameters->subject;
$location = $json->queryResult->parameters->location;
$description = $json->queryResult->parameters->description;
$startDateTime = $json->queryResult->parameters->startDateTime;
$endDateTime = $json->queryResult->parameters->endDateTime;
if($intent== "UnreadMessages"){
$unread = unReadMessages($gmail, $user);
$speech = "You have ".$unread." messages";
}
else if($intent == "GetSchedule"){
$events = get_event($calendar);
if($events){
$reply = "You have the following events coming up:";
foreach($events as $event){
$eventName = $event['eventName'];
$eventTime = $event['time'];
$reply .= $eventName."is at".$eventTime;
}
$speech = $reply;
}
else{
$speech = "You don't have any events coming up.";
}
}
}
I'm suspecting it may be because of the authentication process that's required everytime I try to run the app, since the error only starts popping up whenever I check for session tokens. My problem now is how do I remove this authentication process?

You have several serious issues with your approach here, but most of them result from you treating the interaction with the Google Assistant like it was a browser hitting your web page. Although Actions on Google uses HTTPS and a webhook, it is otherwise not really like a browser at all.
For example, you check $_SESSION to see if an access token has already been set. $_SESSION is typically implemented by setting a session ID in the browser with a session cookie. The Assistant doesn't use cookies at all. Although it has a userStorage object which can be used it similar ways, this is accessed very differently.
It isn't clear if this is what is causing the error, or if the problem is related here somewhere. If you do have error logs, this would be useful to include in the question.
There is a lot that remains unclear. Primarily - where does the auth token come from in the first place in your code.
In a purely web-based OAuth scheme, you'll direct the user to log in using Google Sign In and, as part of that process, request authorization to access their Drive and GMail. Google Sign In for the Assistant doesn't allow you to do that - all it gives you is an Identity Token.
You can use Account Linking to link the Assistant account to your system - but this requires you to have an OAuth server that generates the auth token that the Assistant will give back to you. This is your OAuth token - not one that comes from Google (unless you're proxying it).
If you have a web-based way to get authorization, you can leverage this to provide access through the Assistant as well using Google Sign In for the Assistant.

Related

Access Google My Business Statistics with API in php

I manage approximately 200 Google My business accounts, all being owned under an email XXX#YYY.com
I would like to use the Google My Business API using a PHP SDK to retrieve all types of stats regarding each accounts (ie. view per timeframe, view through map, view through SERP, etc...).
I did get the authorization to use the Google My Business API and I downloaded the php SDK: https://developers.google.com/my-business/samples/google-api-services-mybusiness-v4p9-php-rev-20210224-1.zip?hl=fr
I also created a service account (which I'm really not familiar with) in order to auth with the library.
Now here is my code :
$client = new Google_Client();
$client->useApplicationDefaultCredentials();
// set the service account json file location manually
$client->setAuthConfig(__DIR__.'/../global/yyyyy-xxxx-xxxxxxxxxx.json');
$client->setApplicationName("yyyyyb");
// set the scope to access GMBs
$client->setScopes([
"https://www.googleapis.com/auth/business.manage"
]);
$this->client = $client;
$mybusinessService = new Google_Service_Mybusiness($client);
$accounts = $mybusinessService->accounts;
$accountsList = $accounts->listAccounts()->getAccounts();
echo "<pre>";
print_r($accountsList);
echo "</pre>";
$locationNames = array("Paris");
$insightReqObj = new Google_Service_MyBusiness_ReportLocationInsightsRequest();
$insightReqObj->setLocationNames($locationNames);
$basicReqObj = new Google_Service_MyBusiness_BasicMetricsRequest();
// datetime range is mandatory
// TODO :: validate to not allow more than 18 months difference
$timeRangObj = new Google_Service_MyBusiness_TimeRange();
$timeRangObj->setStartTime("2020-01-01T15:01:23Z");
$timeRangObj->setEndTime("2021-01-11T15:01:23Z");
$metricReqObj = new Google_Service_MyBusiness_MetricRequest();
$metricReqObj->setMetric('ALL');
$basicReqObj->setMetricRequests(array($metricReqObj));
$basicReqObj->setTimeRange($timeRangObj);
$insightReqObj->setBasicRequest($basicReqObj);
$allInsights = $mybusinessService->accounts_locations->reportInsights("accounts/XXXXXXXX",$insightReqObj);
echo "<pre>";
print_r($allInsights);
echo "</pre>";
There are two issues :
When I print the accountlist, I only find information about my service account, I was expecting a list of all the accounts managed by my email : XXX#YYY.com ; I realise that it makes no sense since I don't even know how to grant the service account access to the My Business account managed by this email.
Also AllInsignt generate an error :
How can I access the statistics of all the accounts managed by my Gmail account : XXX#YYY.com ?

Get user login access token to use youtube API

I am using youtube API for scheduling live events for user in my application.
Once the user logged in my application i need to logged in the same user to our business google account(One google account for all user) without giving login credentials. and to get access token for scheduling the live events.
Is it possible to login the user into google account without giving login credentials(User will not feel he is login to another account).
Is it feasible with PHP?.Please give one example to get access token for youtube API access.
I used the following code for getting access token but service account can't access the youtube service.
My code for getting access token using service account:
<?php
require_once 'Google/autoload.php';
session_start();
$client_id = '395540674667-p64tdfqdsfsdfdsf#dsfd.com';
$Email_address = '54564-drgfdg1#developer.gserviceaccount.com';
$key_file_location = 'Youtube API-5czxczxc86.p12';
$client = new Google_Client();
$client->setApplicationName("Youtube API");
$key = file_get_contents($key_file_location);
// seproate additional scopes with a comma
$scopes = array('https://www.googleapis.com/auth/sqlservice.admin','https://www.googleapis.com/auth/plus.login','https://www.googleapis.com/auth/youtube');
$cred = new Google_Auth_AssertionCredentials($Email_address,
$scopes,
$key);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
//print_r($client);
echo $client->getAccessToken();
?>
I am expecting the answer is something like this.Any one please help
you example about Youtube api, first:
select credentials to your api project from here:
https://console.cloud.google.com/home/dashboard?project= with your project
also you need to have the api enable because google told us "Some APIs are enabled automatically."
when you select:
https://console.cloud.google.com/apis/api/youtube/ with Go to Credentials you have some option into modal window this will help
also.
the php code seem to be ok but also I think you will change after you learn more about Credentials settings.

400 Bad Request on Gmail API with php

I want my server to access a gmail account with php code. And the following is what I created with the examples I can find online.
<?php
session_start();
require_once dirname(dirname(__FILE__)) . '/utility/google-api-php-client/src/Google/autoload.php';
$json_file_location = 'Gmail-YQXB-7c754a18211a.json';
$client = new Google_Client();
$service = new Google_Service_Books($client);
$sgmail = new Google_Service_Gmail($client);
$scopes = array('https://www.googleapis.com/auth/books', 'https://mail.google.com');
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$cred = $client->loadServiceAccountJson($json_file_location, $scopes);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$_SESSION['service_token'] = $client->getAccessToken();
$optParams = array('filter' => 'free-ebooks');
$results = $service->volumes->listVolumes('Henry David Thoreau', $optParams);
echo "<h3>Results Of Call:</h3>";
foreach ($results as $item) {
echo $item['volumeInfo']['title'], "<br /> \r\n";
}
$msg = $sgmail->users_messages->listUsersMessages('me');
var_dump($msg);
?>
The code works except the last request, which will throw something like:
PHP Fatal error: Uncaught exception 'Google_Service_Exception' with
message 'Error calling GET
https://www.googleapis.com/gmail/v1/users/me/messages: (400) Bad
Request' in
C:\inetpub\wwwroot\utility\google-api-php-client\src\Google\Http\REST.php:110
$msg = $sgmail->users_messages->listUsersMessages('me');
This account is a Service Account. I could make it working if I use a Web application type Client ID. Just don't know what is wrong here.
You should not be using a service account if you just want to access one account (your own). Service accounts are their own account and they're not Gmail accounts. They work well for APIs that don't need a user (e.g. maps, search) or when you are using a Google Apps for Work domain and want delegation enabled for all users in the domain (by domain admin, so you don't need individual user authorization).
You want to use standard oauth2 web auth flow. If you want to make sure it's usable offline (e.g. by some script/service/cron job) then make sure you add the offline flag on your oauth2 authorization web flow request and that'll make sure you get a permanent refresh token (can be used to request an access token). If you don't set offline, then it's an access token which is only good for an hour. See https://developers.google.com/gmail/api/auth/web-server for more details.

Google Analytics API blank screen when querying accounts?

I am novice to Google Analytics Api. I just started working on a small project where I want to pull data from the API and display it on each user’s Dashboard, using one single Google Analytics Account. I tried to follow the tutorial provided by google and made adjustments where required due to update to the library.
I am working on a codeigniter based platform and I was able to create a Google Client Object and also to make use of a refresh token which is saved in the database. I use the refresh token in order to have the data available on the dashboard without having to manually login every time.
The access token is there every time when I am logged in, and I can use it to set the client access token and create a Google Service Analytics object ($service = new Google_Service_Analytics($client);). I am printing the service and I can see the client id, client secret, etc and the access token being passed to it; but other like Google_Service_Analytics_DataGa_Resource Object are empty ( I do not know if they should be like that or not at this particular step ?).
When I am trying to request the user accounts
$accounts = $analytics->management_accounts->listManagementAccounts();,
I get a blank screen and my view is not being rendered.
I could not find such a problem being encountered before, so I am a bit confused why is happening. I do not get any error messages or anything that might point me to the cause of it or the right direction.
Note: I did managed to make it work using the same credentials trough JavaScript, but in this case it is not what I am looking for. I was able to retrieve data, display data in charts,etc using JS. I am new to making posts, so if anything is required from my part in order for you to have a better idea of what is going on, please do let me know.
I would greatly appreciate it I could get any indication to why that might be happening, or anything that would put me on the right path.
Codeigniter controller Class as follows
// Step 1 - Load PHP Client Libraries
require_once APPPATH.'libraries/Google/Client.php';
require_once APPPATH.'libraries/Google/Analytics.php';
class GoogleTest extends CI_Controller {
public function index(){
$this->load->helper(array('url','form'));
$this->load->model('googleapi_model'); //used to get the refresh token
// Step 2 - Start a session to persist credentials
session_start();
// Step 3 - Create and configure a new client object
$client = new Google_Client();
$client->setApplicationName("API Project");
// Insert client id, api key, client secret, project scope and redirect uri
$client->setDeveloperKey("***************");
$client->setClientId('********************');
$client->setClientSecret('******************');
$client->setRedirectUri('****************');
$client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
// Check if refresh token exists, it is used to login users automatically & it is being generated only once when you login the first time from the created
// google analytics app, this will take precedence to Step 4 or 6 below ;
if(count($this->googleapi_model->getGoogleRefreshToken()) > 0){
$db_refresh_token = $this->googleapi_model->getGoogleRefreshToken();
$client->refreshToken($db_refresh_token[0]->refreshtoken);
$_SESSION['token'] = $client->getAccessToken();
}else{
if ($client->getAccessToken()) {
$token = $client->getAccessToken();
$authObj = json_decode($token);
$refreshToken = $authObj->refresh_token;
if(isset($refreshToken) && $refreshToken != null){
$this->googleapi_model->insertGoogleRefreshToken($refreshToken);
}
}
}
//Step 4 - Handle authorization flow from the server
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
// Step 5 - Retrieve and use stored credentials
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
// Stept 6 - Either prompt the user to login or run the demo
if(!$client->getAccessToken()){
$authUrl = $client->createAuthUrl();
$this->data['auth'] = $authUrl;
}else{ //Create analytics service object
echo 'authenticated';
$analytics = new Google_Service_Analytics($client);
//TILL HERE MY CODE WORKS FINE, NO ERRORS, VIEW BEING RENDERED
$accounts = $analytics ->management_accountSummaries->listManagementAccountSummaries();
// $accounts = $analytics->management_accounts->listManagementAccounts();
echo '<pre>';
print_r($analytics);
echo '</pre>';
}
$this->data['content'] = '/public/dashboard/google_test';
$this->load->view('template/template', $this->data);
}
Make sure you're logged into the google account that API app is in.
And that you have clicked 'connect'.
Then run the script.
Also turn on error reporting (including notices)

Google Apps Marketplace SSO: offline access

Our application is widely-integrated with Google services like Mail, Contacts, Calendar etc. And for all of these Google services we need access to the user's data permanently, without asking the user for permission every time we need to pull our app with data from Google. It's very important to have instant access to the user's data when we sync contacts, calendar or access mail via Google IMAP.
We also provide access to our app from any Google service via Single-Sign-On (SSO). And here we have a trouble.
We are asking users who install our application for "offline" access to their data. So we can have access to their data instantly, when we run our sync scripts etc.
First time user grants access to our app (via SSO, when it clicks on our app icon), it's asked to grant access to all data API we need - contacts, email, calendar etc. Everything goes okay and user gets logged in our app. But when user accesses our app next times (same via SSO), it gets asked to grant "Have offline access". It's very strange, because first time user doesn't get asked for this. And it also doesn't look nice to ask user every time for "offline access". Why we consider such behaviour strange is because once user has already granted access. So why it gets asked again and again?
The code we are using for SSO is as follows:
$clientId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com";
$clientSecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$callback = "https://our_domain/callback";
$scopes = array(
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/drive.readonly.metadata",
"https://www.googleapis.com/auth/calendar",
"https://www.google.com/m8/feeds",
"https://www.googleapis.com/auth/tasks",
"https://www.googleapis.com/auth/admin.directory.user.readonly",
"https://mail.google.com/"
);
// $params is a list of GET and POST parameters
if (empty($params['code']))
{
$_SESSION['GOOGLE_SSO_STATE'] = md5(uniqid(rand(), true));
$client = new Google_Client();
$client->setClientId($clientId);
$client->setRedirectUri($callback);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setState($_SESSION['GOOGLE_SSO_STATE']);
$client->setScopes($scopes);
$url = $client->createAuthUrl();
echo "<script> top.location.href='" . $url . "'</script>";
exit;
}
if (!empty($params['code']) && !empty($params['state']) && $params['state'] == $_SESSION['GOOGLE_SSO_STATE'])
{
unset($_SESSION['GOOGLE_SSO_STATE']);
$client = new Google_Client();
$client->setClientId($clientId);
$client->setClientSecret($clientSecret);
$client->setRedirectUri($callback);
$credentials = $client->authenticate();
// we need refresh token so we can exchange it for new access token when the current ones expires
if (!isset($credentials_['refresh_token']))
{
echo "Wrong credentials received";
exit;
}
$client = new Google_Client();
$client->setUseObjects(true);
$client->setAccessToken($credentials);
$userInfoService = new Google_Oauth2Service($client);
$userInfo = $userInfoService->userinfo->get();
echo $userInfo->getId();
}
Can anyone help us understand this behaviour? Or maybe someone even knows how to make it not asking user for "offline access" every time it accesses the app?
This because your approval prompt is set to "force:
$client->setApprovalPrompt('force');
Use force only if you need to re-issue a refresh token. There is a strange side effect that ask the user time and again for offline access.
We use Service Accounts which provide us with offline access for any user in the installed domain (for the chosen Organiztaion Unit). Depending on what you are trying to do, this may be an option for you.
https://developers.google.com/drive/web/service-accounts

Categories