I'm writing a Wordpress plugin which displays visits on a page. Everything's done and it works perfectly... for an hour. I can't refresh the token when it expires, so the end-user can't see Analytics results. I don't know what am I doing wrong, maybe I misunderstood the authentication process.
This is how I manage the first connection to the API:
$client->setClientId(get_option('client_ID'));
$client->setClientSecret(get_option('client_secret'));
$client->setRedirectUri(get_option('redirectURI'));
$client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
$client->setAccessType('offline');
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'><button>Authorize Google</button></a>";
And then i do this:
try {
if (isset($_GET['code'])) {
$client->authenticate();
$_SESSION['token'] = $client->getAccessToken();
update_option('token', $_SESSION['token']);
$tok = json_decode($_SESSION['token']);
update_option('refresh_token', $tok->refresh_token);
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
?><script type="text/javascript">
window.location="<?php filter_var($redirect, FILTER_SANITIZE_URL)?>";
</script><?php
}
if (isset($_SESSION['token'])) {
update_option('token', $_SESSION['token']);
$client->setAccessToken($_SESSION['token']);
}
} catch (Google_AuthException $e){
return FALSE;
}
This works fine. Now here's the part, where it should use the token thats stored as an option and if it expired, use refresh_token to get a new one automatically. Here's the code:
$client = new Google_Client();
$client->setApplicationName('AnalyticsPK Plugin for Wordpress');
$client->setClientId(get_option('client_ID'));
$client->setClientSecret(get_option('client_secret'));
$client->setRedirectUri(get_option('redirectURI'));
$client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
$client->setAccessType('offline');
$client->setApprovalPrompt("force");
echo "Token: ".get_option('token')."<br>";
echo "Refresh token: ".get_option('refresh_token')."<br>";
$client->setAccessToken(get_option('token'));
if ($client->isAccessTokenExpired()){
echo "Token expired <br>";
$client->refreshToken(get_option('refresh_token'));
echo "New token: ".$client->getAccessToken();
}
//echo "Token: ".get_option('token');
//echo "Refresh token: ".get_option('refresh_token');
// Magic. Returns objects from the Analytics Service instead of associative arrays.
$client->setUseObjects(true);
$analytics = new Google_AnalyticsService($client);
When the token expiration time passes, I get an error:
Fatal error: Uncaught exception 'Google_AuthException' with message
'Error refreshing the OAuth2 token, message: '{ "error" :
"invalid_request", "error_description" : "Client must specify either
client_id or client_assertion, not both" }'' in
/_wpsu/analytics/wp-content/plugins/AnalyticsPK/google-api-php-client/src/auth/Google_OAuth2.php:288
Stack trace: #0
/_wpsu/analytics/wp-content/plugins/AnalyticsPK/google-api-php-client/src/auth/Google_OAuth2.php(248):
Google_OAuth2->refreshTokenRequest(Array) #1
/_wpsu/analytics/wp-content/plugins/AnalyticsPK/google-api-php-client/src/Google_Client.php(311):
Google_OAuth2->refreshToken('1/XCyf8ofh6H3kL...') #2
/_wpsu/analytics/wp-content/plugins/AnalyticsPK/AnalyticsPK.php(90):
Google_Client->refreshToken('1/XCyf8ofh6H3kL...') #3
/_wpsu/analytics/wp-includes/widgets.php(182):
AnalyticsPK->widget(Array, Array) #4 [internal function]:
WP_Widget->display_callback(Array, Array) #5
/_wpsu/analytics/wp-includes/widgets.php(895):
call_user_func_array(Array, Array) #6 /_wpsu/analytics/ in
/_wpsu/analytics/wp-content/plugins/AnalyticsPK/google-api-php-client/src/auth/Google_OAuth2.php
on line 288
What am I doing wrong with refreshing the token?
Related
Hi everyone.
I hope you all are doing well.
I know this question has been asked many times but non of the solutions provided there worked for me.
I am implementing google calendar API in custom PHP. I have followed the official documentation provided by Google. I have been able to create and get events for a specific user.
My original goal was to allow every user to get, create, update and delete Events on their own calendar.
Here's what I have been doing in the code.
This is calendarSetting.php file.
<?php
require __DIR__ . '/vendor/autoload.php';
function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Google Calendar API PHP Quickstart');
$client->setScopes(Google_Service_Calendar::CALENDAR);
$client->setAuthConfig('client_secret.json');
$client->setAccessType('offline');
$client->setPrompt('select_account consent');
$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;
}
?>
This is createCalendar.php file
<?php
require __DIR__ . '/vendor/autoload.php';
include('calendarSetting.php');
session_start();
$appointment_id = $_SESSION['appointment_id'];
$patient_fname = $_SESSION['patient_fname'];
$patient_lname = $_SESSION['patient_lname'];
$patient_phone = $_SESSION['patient_phone'];
$schedule = $_SESSION['appointment_date'];
$start_date = $_SESSION['start'];
$end_date = $_SESSION['end'];
$client = getClient();
$service = new Google_Service_Calendar($client);
$event = new Google_Service_Calendar_Event(array(
'summary' => $patient_fname . ' ' . $patient_lname,
'description' => $patient_fname . ' ' . ' ' . $patient_lname . ' ' . $patient_phone ,
'start' => array(
'dateTime' => $start_date.':00+05:00',
'timeZone' => 'America/Los_Angeles',
),
'end' => array(
'dateTime' => $end_date.':00+05:00',
'timeZone' => 'America/Los_Angeles',
),
'recurrence' => array(
'RRULE:FREQ=DAILY;COUNT=1'
),
'attendees' => array(
array('email' => 'abc1211#gmail.com')
)
));
$calendarId = 'user876#gmail.com';
$event = $service->events->insert($calendarId, $event);
printf('Event created');
header('location: Doctor');
?>
This is perfectly working for the user where $calendarId = 'user876#gmail.com';. but if I change the user it gives me an error.
Fatal error: Uncaught Google\Service\Exception: { "error": { "errors":
[ { "domain": "global", "reason": "notFound", "message": "Not Found" }
], "code": 404, "message": "Not Found" } } in
F:\xampp\htdocs\bupa1\vendor\google\apiclient\src\Http\REST.php:128
Stack trace: #0
F:\xampp\htdocs\bupa1\vendor\google\apiclient\src\Http\REST.php(103):
Google\Http\REST::decodeHttpResponse(Object(GuzzleHttp\Psr7\Response),
Object(GuzzleHttp\Psr7\Request), 'Google_Service_...') #1 [internal
function]: Google\Http\REST::doExecute(Object(GuzzleHttp\Client),
Object(GuzzleHttp\Psr7\Request), 'Google_Service_...') #2
F:\xampp\htdocs\bupa1\vendor\google\apiclient\src\Task\Runner.php(182):
call_user_func_array(Array, Array) #3
F:\xampp\htdocs\bupa1\vendor\google\apiclient\src\Http\REST.php(66):
Google\Task\Runner->run() #4
F:\xampp\htdocs\bupa1\vendor\google\apiclient\src\Client.php(898):
Google\Http\REST::execute(Object(GuzzleHttp\Client),
Object(GuzzleHttp\Psr7\Request), 'Google_Service_...', Array, NULL) #5
F:\x in
F:\xampp\htdocs\bupa1\vendor\google\apiclient\src\Http\REST.php on
line 128
I have been trying to figure out why is this happening. so far what I found is that each time when i send a request to google to create the event my access token in the calendarSetting.php file isn't refreshing.
Now I got stuck on how can I get the refresh token so that a new user could also create events.
If anybody could help to figure this out I'll be very grateful.
Thank you
What you have right now will end up being a single user system. If the file exists then no one else will need to login. If you start deleting that file then what about if user one is still using the system they will then be reading data using user twos token from the file.
If this is a web app you should be using session vars.
oauth2callback.php
require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/Oauth2Authentication.php';
// Start a session to persist credentials.
session_start();
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$client = buildClient();
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client = buildClient();
$client->authenticate($_GET['code']); // Exchange the authencation code for a refresh token and access token.
// Add access token and refresh token to seession.
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
//Redirect back to main script
$redirect_uri = str_replace("oauth2callback.php",$_SESSION['mainScript'],$client->getRedirectUri());
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
Oauth2Authentication.php
You should check the full link for all the code in this file. Notice how it stores the users tokens in the session vars so each user has its own tokens stored in its browser.
function getOauth2Client() {
try {
$client = buildClient();
// Set the refresh token on the client.
if (isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
$client->refreshToken($_SESSION['refresh_token']);
}
// 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']);
// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$client->setAccessToken($client->getAccessToken());
$_SESSION['access_token'] = $client->getAccessToken();
}
return $client;
} else {
// We do not have access request access.
header('Location: ' . filter_var( $client->getRedirectUri(), FILTER_SANITIZE_URL));
}
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
}
I am trying to use Google APIs with craft cms. To pull data from my calendar from Google. I modify the quickstsrt.php that Google had on Github. That works but when I went to add the code to my Craft plugin it's not able to find the JSON file anymore
I have the same code working outside of craft. I have gone through the google results and was not able to find any solution that would work. it may be the why I authorized my google account but like I said the PHP works outside of craft
public function getClient()
{
$client = new Google_Client();
$client->setApplicationName('Google Calendar API PHP Quickstart');
$client->setScopes(Google_Service_Calendar::CALENDAR_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;
InvalidArgumentException: file "/home/mesicdev/www/craft/plugins/credentials.json" does not exist in /home/mesicdev/public_html/craft/plugins/calendarpuller/src/services/vendor/google/apiclient/src/Google/Client.php:870
Stack trace:
0 /home/mesicdev/public_html/craft/plugins/calendarpuller/src/services/CalendarService.php(87): Google_Client->setAuthConfig('/home/mesicdev/...')
1 /home/mesicdev/public_html/craft/plugins/calendarpuller/src/services/CalendarService.php(60): campnonet\calendarpuller\services\CalendarService->getClient()
2 /home/mesicdev/public_html/craft/plugins/calendarpuller/src/controllers/CalendarController.php(63): campnonet\calendarpuller\services\CalendarService->getCalendarInfo()
3 [internal function]: campnonet\calendarpuller\controllers\CalendarController->actionDefault(true)
4 /home/mesicdev/public_html/craft/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
5 /home/mesicdev/public_html/craft/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
6 /home/mesicdev/public_html/craft/vendor/craftcms/cms/src/web/Controller.php(109): yii\base\Controller->runAction('default', Array)
7 /home/mesicdev/public_html/craft/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('default', Array)
8 /home/mesicdev/public_html/craft/vendor/craftcms/cms/src/web/Application.php(297): yii\base\Module->runAction('calendar-puller...', Array)
9 /home/mesicdev/public_html/craft/vendor/yiisoft/yii2/web/Application.php(103): craft\web\Application->runAction('calendar-puller...', Array)
10 /home/mesicdev/public_html/craft/vendor/craftcms/cms/src/web/Application.php(286): yii\web\Application->handleRequest(Object(craft\web\Request))
11 /home/mesicdev/public_html/craft/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
12 /home/mesicdev/public_html/craft/web/index.php(21): yii\base\Application->run()
13 {main}
you have an error in this line
$client->setAuthConfig(credentials.json);
This should be a path to a real file.
use this instead:
$client->setAuthConfig("/path/to/credentials.json");
I am wrong for whatever reason I forgot to add the /src folder when typing my path to json Thaks for your help
there i found some error, when i want to make sure the session on Login with google account. And the error is :
Fatal error: Uncaught InvalidArgumentException: Invalid token format in C:\xampp\htdocs\google\googleAPI\src\Google\Client.php:434 Stack trace: #0 C:\xampp\htdocs\google\callback.php(5): Google_Client->setAccessToken(Array) #1 {main} thrown in C:\xampp\htdocs\google\googleAPI\src\Google\Client.php on line 434
and then this is my code :
<?php
require_once('config.php');
if (isset($_SESSION['accessToken'])){
$client->setAccessToken($_SESSION['accessToken']);
}
else if (isset($_GET['code'])) {
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$_SESSION['accessToken'] = $token;
}
else{
header("location: index.php");
}
$oAtuth = new Google_Service_Oauth2($client);
$user = $oAtuth->userinfo->get();
echo "<pre>";
print_r($user);
?>
Please tell me whats wrong with this code
You have wrong value of token in $_SESSION['accessToken'].
I am trying to access a users contact list using google Oauth2 but seem to be running into an error insufficient permision. My code is as below
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Google extends CI_Controller {
public function __construct() {
parent::__construct();
}
public function index() {
require_once 'google-api-php-client/autoload.php'; // or wherever
autoload.php is located
$client = new Google_Client();
$scriptUri = "http://localhost/tcaller/google/";
$client = new Google_Client();
$client->setAccessType('online'); // default: offline
$client->setApplicationName('Tcaller');
$client->setClientId('******');
$client->setClientSecret('****');
$client->setRedirectUri($scriptUri);
$client->setDeveloperKey('******'); // API key
$client->setScopes(array('https://www.google.com/m8/feeds' , 'https://www.googleapis.com/auth/contacts.readonly'));
$plus = new Google_Service_Plus($client);
if (isset($_GET['logout'])) { // logout: destroy token
$this->session->unset_userdata("token");
die('Logged out.');
}
if (isset($_GET['code'])) { // we received the positive auth callback, get the token and store it in session
$client->authenticate($_GET['code']);
$tokenArr = array('token' => $client->getAccessToken());
$this->session->set_userdata($tokenArr);//gets valid access token
$redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']; //set into session storage
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
if ($this->session->userdata('token')) { // extract token from session and configure client
$token = $this->session->userdata('token');
$client->setAccessToken($token);
try {
$me = $plus->people->get('me');
print_r($me);
} catch (apiServiceException $e) {
// Handle exception. You can also catch Exception here.
// You can also get the error code from $e->getCode();
echo 'error';
}
}
if (!$client->getAccessToken()) { // auth call to google
$authUrl = $client->createAuthUrl();
header("Location: ".$authUrl);
die();
}
}
}
?>
I am getting the error
Fatal error: Uncaught exception 'Google_Service_Exception' with
message 'Error calling GET
https://www.googleapis.com/plus/v1/people/me?key=%2A%2A%2A%2A%2A%2A:
(403) Insufficient Permission' in
C:\xampp\htdocs\tcaller\application\controllers\google-api-php-client\src\Google\Http\REST.php:111
Stack trace: #0
C:\xampp\htdocs\tcaller\application\controllers\google-api-php-client\src\Google\Http\REST.php(63):
Google_Http_REST::decodeHttpResponse(Object(Google_Http_Request),
Object(Google_Client)) #1 [internal function]:
Google_Http_REST::doExecute(Object(Google_Client),
Object(Google_Http_Request)) #2
C:\xampp\htdocs\tcaller\application\controllers\google-api-php-client\src\Google\Task\Runner.php(172):
call_user_func_array(Array, Array) #3
C:\xampp\htdocs\tcaller\application\controllers\google-api-php-client\src\Google\Http\REST.php(47):
Google_Task_Runner->run() #4
C:\xampp\htdocs\tcaller\application\controllers\google-api-php-client\src\Google\Client.php(564):
Google_Http_REST::execute(Object(Google_Client), Object(Google_H in
C:\xampp\htdocs\tcaller\application\controllers\google-api-php-client\src\Google\Http\REST.php
on line 111
Am i missing something
You should not need to use a separate API key and call $client->setDeveloperKey() as you're obtaining and using an OAuth 2.0 access token already with a client secret. Moreover, it seems that that is incorrect and/or not associated with the same project. So please try with that call removed.
I'm attempting to use the Google Calendar API version3 (PHP) to manage calendars.
I can easily retrieve information regarding a calendar such as calendar names and calendar lists, but I am unsuccessful in actually 'writing' to a calendar such as adding events or creating a secondary calendar. I always receive the following error in my attempt.
Anybody out there that can help? I have looked everywhere in Google's documentation but can't find any answers.
The error (if trying to post, not retrieve info):
Fatal error: Uncaught exception 'apiServiceException' with message 'Error calling POST https://www.googleapis.com/calendar/v3/calendars?key=eyfheufheuwehwi: (400) Invalid Value' in /home/incs/google-api-php-client/src/io/apiREST.php:86 Stack trace: #0 /home/incs/google-api-php-client/src/io/apiREST.php(56): apiREST::decodeHttpResponse(Object(apiHttpRequest)) #1 /home/incs/google-api-php-client/src/service/apiServiceResource.php(187): apiREST::execute(Object(apiServiceRequest)) #2 /home/incs/google-api-php-client/src/contrib/apiCalendarService.php(228): apiServiceResource->__call('insert', Array) #3 /home/public_html/gateway/google/index.php(130): CalendarsServiceResource->insert(Object(Calendar)) #4 {main} thrown in /home/incs/google-api-php-client/src/io/apiREST.php on line 86
the code (by the way my access keys are set in the config.php hence the commented $client lines)
require("/home/incs/google-api-php-client/src/apiClient.php");
require("/home/incs/google-api-php-client/src/contrib/apiCalendarService.php");
session_start();
$client = new apiClient();
$client->setApplicationName("Google Calendar PHP Starter Application");
// Visit https://code.google.com/apis/console?api=calendar to generate your
// client id, client secret, and to register your redirect uri.
// $client->setClientId('insert_your_oauth2_client_id');
// $client->setClientSecret('insert_your_oauth2_client_secret');
// $client->setRedirectUri('insert_your_oauth2_redirect_uri');
// $client->setDeveloperKey('insert_your_developer_key');
$service = new apiCalendarService($client);
if (isset($_GET['logout']))
{
unset($_SESSION['token']);
}
if (isset($_GET['code']))
{
$client->authenticate();
$_SESSION['token'] = $client->getAccessToken();
header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
}
if (isset($_SESSION['token']))
{
$client->setAccessToken($_SESSION['token']);
}
if ($client->getAccessToken())
{
$calendar = new Calendar();
$calendar->setSummary('calendarSummary');
$calendar->setTimeZone('American/Los_Angeles');
$createdCalendar = $service->calendars->insert($calendar);
$calList = $service->calendarList->listCalendarList();
print "<h1>Calendar List</h1><pre>" . print_r($calList, true) . "</pre>";
$_SESSION['token'] = $client->getAccessToken();
}
else
{
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Connect Me!</a>";
}
As it is right now, Google has an error in their code sample (which is where I got the code that I pasted here). In that sample the following needs to be corrected for it to work:
$calendar->setTimeZone('American/Los_Angeles');
needs to be corrected to
$calendar->setTimeZone('America/Los_Angeles');
And then no error will be thrown.