Use Authenticated Google Client instance for multiple services - php

I am creating google client instance and authenticating it once and fetching required data. Afterwards if I want to use that same instance of Google client for some other service , how can I achieve it ?
webmasterMain route is my redirect uri registered in google webmaster .
public function webmasterMain(Request $request)
{
$requestData = $request->all();
if ($request->isMethod('POST') || isset($requestData['code'])) {
$google_redirect_url = env('APP_URL') . '/user/webmasterMain';
$gClient = new \Google_Client();
$gClient->setAccessType("offline");// to get refresh token after expiration of access token
$gClient->setIncludeGrantedScopes(true); // incremental auth
$gClient->setApplicationName(config('services.google.app_name'));
$gClient->setClientId(config('services.google.client_id'));
$gClient->setClientSecret(config('services.google.client_secret'));
$gClient->setRedirectUri($google_redirect_url);
$gClient->setDeveloperKey(config('services.google.api_key'));
$gClient->setScopes(array(
'https://www.googleapis.com/auth/plus.me',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/webmasters.readonly',
'https://www.googleapis.com/auth/webmasters',
));
$google_oauthV2 = new \Google_Service_Oauth2($gClient);
if ($request->get('code')) {
$gClient->authenticate($request->get('code'));
$request->session()->put('token', $gClient->getAccessToken());
}
if ($request->session()->get('token')) {
$gClient->setAccessToken($request->session()->get('token'));
}
if ($gClient->getAccessToken()) {
$inst = new Google_Service_Webmasters($gClient);
$res = $inst->sites->listSites();
$sites = $res->getSiteEntry();
$siteUrl = [];
foreach ($sites as $key => $site) {
$siteUrl = array_add($siteUrl, $key, ['site_name'=>$site['siteUrl'], 'site_permission_level' => $site['permissionLevel']]);
}
$sites = (((array)$siteUrl));
return view('User::webmasterMain')->with(['data' => $sites]);
} else {
//For Guest user, get google login url
$authUrl = $gClient->createAuthUrl();
return redirect()->to($authUrl);
}
}
return view('User::webmasterMain');
}
Now suppose I want to get the authenticated $gClient for service like Google_Service_Webmasters_SearchAnalyticsQueryRequest , then how can I make $client = $gClient for this next request ?
public function query(Request $request){
//suppose $client is the same instance which was previously authenticated and stored in $gClient
$website = "http://example.com/";
$searchAnalytics = new \Google_Service_Webmasters_SearchAnalyticsQueryRequest();
$searchAnalytics->setStartDate('2017-03-01');
$searchAnalytics->setEndDate('2017-03-31');
$searchAnalytics->setDimensions(['page']);
$searchAnalytics->setSearchType('web');
`$results = $client->searchanalytics->query($website, $searchAnalytics);`
return $results->getRows();

I got the answer , no need to save the instance or do anything but, follow this :
Create a Google Client Object.
At first time authenticating save the accessToken from google client object by getAccessToken().
Use the same access token and set Access token in this google client.
now you can use this google client object for any service.
First time authenticating:
$gClient = new \Google_Client();
//after authenticating
$request->session()->put('token', $gClient->getAccessToken());
Now we can use this access token in any google service call:
$gClient = new \Google_Client();
if ($request->session()->get('token')) {
$gClient->setAccessToken($request->session()->get('token'));
}
$client = new Google_Service_Webmasters($gClient);

Related

Set Google Account on Server side without showing dialog for account selection

This is code from which I get GA data but it is always ask in browser for account selection. How to define default account in PHP script.
What I missing?
This is equal to index.php in GA documentation but I use Symfony framework and decided to change this route
/**
* #Route("/get-google-analytics-data")
*/
public function getGoogleAnalyticsData () {
$ga = $this->get('google_analytics_service');
$client = new \Google_Client();
$client->setAuthConfig(__DIR__ . '/client_secrets.json');
$client->addScope(\Google_Service_Analytics::ANALYTICS_READONLY);
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Create an authorized analytics service object.
$analytics = new \Google_Service_AnalyticsReporting($client);
// Call the Analytics Reporting API V4.
$response = $ga->getReport($analytics);
// Print the response.
return new \Symfony\Component\HttpFoundation\Response($ga->printResults($response));
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
return $this->redirect($redirect_uri);
}
This is equal to oauth2callback.php in GA documentation.
}
/**
* #Route("/oauth2callback", name="gaOA2callback")
*/
public function gaOA2callback () {
$client = new \Google_Client();
$client->setAuthConfig(__DIR__ .'/client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER["HTTP_HOST"] . '/oauth2callback');
$client->addScope(\Google_Service_Analytics::ANALYTICS_READONLY);
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
return $this->redirect($auth_url);
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/get-google-analytics-data';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
return $this->redirect($redirect_uri);
}
}
First of all, this was a bad idea. I had use wrong way of communicate with GA API.
function initializeAnalytics()
{
// Use the developers console and download your service account
// credentials in JSON format. Place them in this directory or
// change the key file location if necessary.
$KEY_FILE_LOCATION = __DIR__ . '/service-account-credentials.json';
// Create and configure a new client object.
$client = new \Google_Client();
$client->setApplicationName("Hello Analytics Reporting");
$client->setAuthConfig($KEY_FILE_LOCATION);
$client->setScopes(['https://www.googleapis.com/auth/analytics.readonly', 'https://www.googleapis.com/auth/analytics']);
$analytics = new \Google_Service_AnalyticsReporting($client);
return $analytics;
}
You can see .json file included in function. This file you can download from Google console Dashboard from your OAuth 2.0 client IDs
.
https://console.developers.google.com/apis/credentials?project=&authuser=1
If you do not have those you will ned to create a new one.
Most important thing, enter a valid VIEW_ID, if you do not do that you
will get permission denied error and probably you will look for
solution on other places.
About permission, user of this API is not your email. it is service email, zou will find it in .json file. And also you will need to set roles for that service email. For basic use view permissions will be just fine.
At end, to get data you can do that with function like this.
$VIEW_ID = "123625914"; // **view ID is look like this, you will find bunch of those vieew on GA Reporting Dashboard for your project.**
function getReport($analytics, $nameSystem) {
// Replace with your view ID, for example XXXX.
$VIEW_ID = "123625914";
// Create the DateRange object.
$dateRange = new \Google_Service_AnalyticsReporting_DateRange();
$dateRange->setStartDate("4000daysAgo");
$dateRange->setEndDate("today");
$today = new \Google_Service_AnalyticsReporting_DateRange();
$today->setStartDate("today");
$today->setEndDate("today");
// Create the Metrics object.
$views = new \Google_Service_AnalyticsReporting_Metric();
$views->setExpression("ga:pageviews");
$views->setAlias("views");
$user = new \Google_Service_AnalyticsReporting_Metric();
$user->setExpression("ga:users");
$user->setAlias("user");
$country = new \Google_Service_AnalyticsReporting_Dimension();
$country->setName("ga:country");
$continent = new \Google_Service_AnalyticsReporting_Dimension();
$continent->setName("ga:continent");
$event = new \Google_Service_AnalyticsReporting_Dimension();
$event->setName("ga:eventLabel");
$event->setName("ga:eventCategory");
// Create the ReportRequest object.
$request = new \Google_Service_AnalyticsReporting_ReportRequest();
$request->setViewId($VIEW_ID);
$request->setDateRanges([$dateRange, $today]);
$request->setMetrics(array($views, $user));
$request->setDimensions(array($event));
$request->setFiltersExpression('ga:eventCategory==' . $nameSystem);
$request1 = new \Google_Service_AnalyticsReporting_ReportRequest();
$request1->setViewId($VIEW_ID);
$request1->setDateRanges([$dateRange, $today]);
$request1->setMetrics(array($user));
$request1->setDimensions(array($continent, $event));
$request->setFiltersExpression('ga:eventCategory==' . $nameSystem);
$request2 = new \Google_Service_AnalyticsReporting_ReportRequest();
$request2->setViewId($VIEW_ID);
$request2->setDateRanges([$dateRange, $today]);
$request2->setMetrics(array($user));
$request2->setDimensions(array($event));
$request2->setFiltersExpression('ga:eventCategory==' . $nameSystem);
$body = new \Google_Service_AnalyticsReporting_GetReportsRequest();
$body->setReportRequests( array( $request, $request1, $request2) );
return $analytics->reports->batchGet( $body );
}

Google Sheet Access Token

I am a bit confused on the Access token. I have written a PHP script which inserts the data I get from the POST request , I already have authorized the App and it does add the Row at the end of the Sheet.
My Question is how I refresh the token when it get implemented on the server, as it will add the POST data.
Here is the Code
<?php
// Load the Google API PHP Client Library.
require_once __DIR__ . '/vendor/autoload.php';
session_start();
$client = new Google_Client();
$client->setAuthConfigFile(__DIR__ . '/client_secrets.json');
$client->addScope(Google_Service_Sheets::SPREADSHEETS);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$lead = array (
"first_name" => $_POST['name'],
"email" => $_POST['email']
);
$sid = "sheet id on which the row is added";
addRowToSpreadsheet($lead, $client , $sid);
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/fb/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
function addRowToSpreadsheet($ary_values = array(), $client , $sid) {
$sheet_service = new Google_Service_Sheets($client);
$fileId = $sid;
$values = array();
foreach( $ary_values AS $d ) {
$cellData = new Google_Service_Sheets_CellData();
$value = new Google_Service_Sheets_ExtendedValue();
$value->setStringValue($d);
$cellData->setUserEnteredValue($value);
$values[] = $cellData;
}
// Build the RowData
$rowData = new Google_Service_Sheets_RowData();
$rowData->setValues($values);
// Prepare the request
$append_request = new Google_Service_Sheets_AppendCellsRequest();
$append_request->setSheetId(0);
$append_request->setRows($rowData);
$append_request->setFields('userEnteredValue');
// Set the request
$request = new Google_Service_Sheets_Request();
$request->setAppendCells($append_request);
// Add the request to the requests array
$requests = array();
$requests[] = $request;
// Prepare the update
$batchUpdateRequest = new Google_Service_Sheets_BatchUpdateSpreadsheetRequest(array(
'requests' => $requests
));
try {
// Execute the request
$response = $sheet_service->spreadsheets->batchUpdate($fileId, $batchUpdateRequest);
if( $response->valid() ) {
// Success, the row has been added
return true;
}
} catch (Exception $e) {
// Something went wrong
error_log($e->getMessage());
}
return false;
}
?>
I have tried hosting the app on the server and it doesn't add a new row in the Sheet, I think this is a problem due to the Access Token
Please Help
There is actually a PHP Quickstart for Sheets API which includes how to refresh tokens. Here's a snippet:
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
There's also a Refreshing an access token (offline access) guide with regard to refresh tokens
Access tokens periodically expire. You can refresh an access token
without prompting the user for permission (including when the user is
not present) if you requested offline access to the scopes associated
with the token.
If you use a Google API Client Library, the client object refreshes
the access token as needed as long as you configure that object for
offline access. If you are not using a client library, you need to set
the access_type HTTP query parameter to offline when redirecting the
user to Google's OAuth 2.0 server. In that case, Google's
authorization server returns a refresh token when you exchange an
authorization code for an access token. Then, if the access token
expires (or at any other time), you can use a refresh token to obtain
a new access token.
If your application needs offline access to a Google API, set the API
client's access type to offline:
$client->setAccessType("offline");

Google Calendar API not working offline. where do I get refresh token in codeigniter controller

I'm using Google Calendar API to display events on fullcalendar(so using a json object in my view). I'm using codeignitor php framework, and I have a few functions in my controller to create a new client then I use that in the oauth2callback() function to exchange my code for an access_token then I start calling the service in gcalendar() and gcalendar_events. I have set the accessType to offline but that doesn't seem to make me access the events offline. It works great except that I'm redirected to log in again every time the session ends. I don't want that, I want them to display all the time after the session ends. I am trying to use a refresh token in case the access_token expires to see if that would fix the problem.
this is the code in my controller
function getClient() {
$client = new Google_Client();
$client->setApplicationName("DL Calendar");
$client->setAuthConfig('application/client_secrets.json');
$client->addScope('profile');
$client->setIncludeGrantedScopes(true);
$client->setAccessType('offline');
return $client;
}
function gcalendar() {
$this->load->add_package_path(APPPATH . 'vendor/autoload');
$client = $this->getClient();
//$client->setRedirectUri(site_url('calendar/index'));
$client->addScope(Google_Service_Calendar::CALENDAR);
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$access_token = $_SESSION['access_token'];
$service = new ]Google_Service_Calendar($client);
$calendar = new Google_Service_Calendar_Calendar();
//$calendarList = $service->calendarList->listCalendarList();
$calendar = $service->calendars->get('primary');
$params = array(
'owner_id' => get_current_user_id(),
'title' => get_current_user(). ' ' .'Google Calendar',
'type' => 'gcal',
'url' => $calendar->id,
);
$calendar_id = $this->Calendar_model->add_calendar($params);
redirect('calendar/index');
} else {
$redirect_uri = site_url('calendar/oauth2callback');
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
$this->session->set_flashdata('success', 'Event Successfully Added');
}
function oauth2callback() {
//Build the client object
$client = $this->getClient();
$client->addScope(Google_Service_Calendar::CALENDAR);
$service = new Google_Service_Calendar($client);
$url = parse_url($_SERVER['REQUEST_URI']); parse_str($url['query'], $params);
$code = $params['code'];
//To exchange an authorization code for an access token, use the authenticate method:
if (! isset($code)) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$token = $client->fetchAccessTokenWithAuthCode($code);
$client->setAccessToken($token);
$client->authenticate($code);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = site_url('calendar/gcalendar');
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
}
function gcalendar_events() {
$client = $this->getClient();
$client->addScope(Google_Service_Calendar::CALENDAR);
// $client->setRedirectUri(site_url('calendar/gcalendar'));
$client->setAccessType('offline'); //need calendar events to appear even if not logged in to google
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
$client->setAccessToken($_SESSION['access_token']);
$access_token = $_SESSION['access_token'];
$service = new Google_Service_Calendar($client);
$id = 'primary';
$calendar = new Google_Service_Calendar_Calendar();
$calendar = $service->calendars->get('primary');
$event = new Google_Service_Calendar_Event();
$events = $service->events->listEvents($id);
foreach ($events->getItems() as $event) {
$startTime = strtotime($event->getStart()->dateTime) ;
$endTime = strtotime($event->getEnd()->dateTime);
$start = date('Y-m-d H:i:s', $startTime);
$end = date('Y-m-d H:i:s', $endTime);
$eventsArr[] = array(
'title' => $event->getSummary(),
'start'=> $start,
'end' => $end,
);
}
// Return a single `events` with all the `$eventsArr`
echo json_encode($eventsArr);
}
}
Is the problem in my session ending? or does the access token expire and I need a refresh token? where do I set the refresh token cause I tried putting it in more that one place and I get an error message that refresh token has to be set as part off setAccessToken. I put it all over and still got error messages.
Here is the code I used
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($refresh_token);
$_SESSION['access_token'] = $refresh_token;
$this->load->helper('file');
write_file('application/client_secrets.json', json_encode($client->getAccessToken()));
} else {
$access_token = $_SESSION['access_token'];
}
I just noticed that it once used to say 'grant offline access' in my authorization but now it no longer mentions that while google documentation says
After a user grants offline access to the requested scopes, you can
continue to use the API client to access Google APIs on the user's
behalf when the user is offline. The client object will refresh the
access token as needed.
I think this Offline access in OAuth guide might help you. Since you're using PHP, try setting the access type to "offline".
If your application needs offline access to a Google API, set the API client's access type to offline:
$client->setAccessType("offline");
After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

How to fetch auth token for service account using google API?

I have a Wordpress site (running PHP) that needs to display its own analytics data to visitors using the google-api. I want to create the charts in Javascript, so I need to fetch an auth token from the PHP code and then pass that to the Javascript code. I can't figure out how to get the auth token.
So far, I have code similar to this working using my service account:
https://github.com/google/google-api-php-client/blob/master/examples/service-account.php
My code:
$client = new Google_Client();
$client->setAuthConfig($credentialsFilePath);
$client->addScope('https://www.googleapis.com/auth/analytics.readonly');
$client->setApplicationName("GoogleAnalytics");
$analytics = new Google_Service_Analytics($client);
$ga = $analytics->data_ga;
$start = date('Y-m-d', strtotime('-7 days'));
$end = date('Y-m-d');
$views = $ga->get('ga:'.$myAnalyticsId,
$start,
$end,
'ga:pageviews,ga:sessions,ga:newUsers',
array(
'dimensions' => 'ga:date',
'sort' => 'ga:date'
));
This all works, and I'm able to connect to Google_Service_Analytics and fetch analytics data. However, I can't figure out how to fetch a service access token using my credentials, that I can hand off to the Javascript code so I can use the Google Analytics API from Javascript.
This doesn't work:
$token = $client->getAccessToken();
Token just ends up being null. What do I need to do to fetch a token?
Here is the working code for me.
The service account has a different type of process for generating access token.
It is not following oauth client api.
//include_once 'vendor/autoload.php';
$credentialsFilePath = 'test.json';
$client = new Google_Client();
$client->setAuthConfig($credentialsFilePath);
$client->addScope('https://www.googleapis.com/auth/analytics.readonly');
$client->setApplicationName("GoogleAnalytics");
$client->refreshTokenWithAssertion();
$token = $client->getAccessToken();
print_r($token);
$accessToken = $token['access_token'];
Figured this out:
$client->refreshTokenWithAssertion();
$token = $client->getAccessToken();
$accessToken = $token['access_token'];
First answer still works in 2021 (Thanks!), but a used function is deprecated (still available though)
This worked for me
public function getToken() {
$client = new Client(); // use Google\Client;
$client->setAuthConfig('securejsonfile.json');
$client->addScope('https://www.googleapis.com/auth/cloud-platform');
$client->setApplicationName('appname');
$client->fetchAccessTokenWithAssertion();
return $client->getAccessToken(); //array
}

Google API with PHP calling google_client object

I'm using codeigniter 3.x and php 5.5+. I've been trying to get this to work with no luck. I want to call methods inside a youtube controller class I created that will do different things based on communicating with the google or youtube. The problem is with the Google_Client I believe or it's with how to store $client variable maybe so you can use it in second function. When I try calling this from another function it gives a not login required error even thought the user already did the google verification. How can I tell my second function that the user has already done the authorization and got the token. Everything seems to work very well when both functions are in the same function(I mean just using one function). Also I don't want to verify user on every function or method I execute.
So after first function is done, I get redirected with an access token in the url to the second function but then I get an error Message: Error calling GET https://www.googleapis.com/youtube/analytics/v1/reports?ids=channel%3D%3DMINE&start-date=2014-01-01&end-date=2016-01-20&metrics=views&filters=video%3D%3DpC900o6JaMc: (401) Login Required
First function in the controller Youtubeverify:
class Youtubeverify extends CI_Controller{
public function youtube_consent(){
$this->load->library('google');
$OAUTH2_CLIENT_ID = 'MY_ID';
$OAUTH2_CLIENT_SECRET = 'MY_KEY';
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes(array('https://www.googleapis.com/auth/yt-analytics-monetary.readonly','https://www.googleapis.com/auth/youtube.readonly'));
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . "/ci/youtubeverify/display_report",
FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);
$youtubeReporting = new Google_Service_YouTubeReporting($client);
if (isset($_REQUEST['logout'])) {
$this->session->unset_userdata('youtube_token');
}
if (isset($_GET['code'])) {
if (strval($_SESSION['state']) !== strval($_GET['state'])) {
die('The session state did not match.');
}
$client->authenticate($_GET['code']);
$youtube_token = $client->getAccessToken();
//trying to store the access token in a session
$newdata = array('youtube_token'=>$youtube_token);
$this->session->set_userdata($newdata);
header('Location: ' . $redirect);
}
if ($this->session->userdata('youtube_token')) {
$client->setAccessToken($this->session->userdata('youtube_token'));
}
if ($client->getAccessToken()) {
$client->getAccessToken();
}
else {
// If the user hasn't authorized the app, initiate the OAuth flow
$state = mt_rand();
$client->setState($state);
$_SESSION['state'] = $state;
$authUrl = $client->createAuthUrl();
redirect($authUrl);
}
}
Second function in the controller Youtubeverify:
public function display_report(){
$this->load->library('google');
$client = new Google_Client();
$client->getAccessToken();
$youtubeAnalytics = new Google_Service_YouTubeAnalytics($client);
$id = 'channel==MINE';
$start_date = '2014-01-01';
$end_date = '2016-01-20';
$optparams = array('filters' => 'video==*********');
$metrics = array('views');
$api_response = $metrics;
$api = $youtubeAnalytics->reports->query($id, $start_date, $end_date, $metric,$optparams);
$data['api_response'] = $api_response['views'];
$this->load->view('layouts/mainlay',$data);
}
I have never worked with YouTube API before, but here's a step in the right direction.
class Youtubeverify extends CI_Controller {
// Google API Keys
const CLIENT_ID = '';
const CLIENT_SECRET = '';
// We'll store the client in a class property so we can access it between methods.
protected $Client;
public function __construct () {
parent::__construct();
// setup google client.
$this->Client = new Google_Client();
$this->Client->setClientId(self::CLIENT_ID);
$this->Client->setClientSecret(self::CLIENT_SECRET);
// we call the authenication method for each request
$this->_authenticate_client();
}
// Authentication method
protected function _authenticate_client () {
//if we already have a token then we just set it in the client
//without going through authentication process again
if( $accessToken = $this->session->userdata('youtube_token') ) {
$this->Client->setAccessToken($accessToken);
}else{
// preform authentication as usual with a redirect ...etc
}
}
}

Categories