Google api authorization for long time - php

I'm trying to make some script, that will automatically add an event from Joomla add new page to a Google calendar. I made it with this code and it even works, but only for a small amount of time.
I maybe misunderstood, how the Google authorization works. First i must authorize the script to use that calendar and so on. I made it once but after an hour i had to do it again. I would like to authorize it forever or at least for one year (something longer than one hour). And i can't even authorize it during the saving process, because its in saving script, that automatically redirect back to post management.
One more thing to mention: there is an redirect uri and i set it on index.php of administration pages. Not sure if its a problem, but it shouldn't because news are added at index.php?...... so it's still the same page.
But it all works for an hour (or something around that) so i believe that problem is not redirect uri.
THX
here is my code (its copy pasted from some google api example page):
require_once "google-api-php-client/src/Google_Client.php";
require_once "google-api-phpclient/src/contrib/Google_CalendarService.php";
session_start();
$client = new Google_Client();
$client->setApplicationName("Add Google Calendar Entries");
$client->setClientId('####');
$client->setClientSecret('####');
$client->setRedirectUri('####');
$client->setDeveloperKey('####');
$cal = new Google_CalendarService($client);
if (isset($_GET['logout'])) {
unset($_SESSION['token']);
}
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
header('Location: http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']);
}
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
}
if ($client->getAccessToken()) {
$calList = $cal->calendarList->listCalendarList();
$_SESSION['token'] = $client->getAccessToken();
$event = new Google_Event();
// some calendar adding stuff
} else {
$authUrl = $client->createAuthUrl();
print "<a class='login' href='$authUrl'>Authorize!</a>";
}
// Google Calendar API END
}
Just to summarize: I want my authorization to work longer and maybe there is a mistake in my code or in my understanding of how that works.

The key piece to get long term access if to request "offline" access from the user when you request authorization.
$client->setAccessType('offline');
$authUrl = $client->createAuthUrl();
This should return a refresh token as well as the current session token. You MUST save this refresh token. Even if they authorize the app again later, the refresh token will NOT be sent again. (And on that note, if they are already authorized and you have them authorize again after adding offline access, sometimes you won't get the refresh token.)
Then you can do a check like the following to keep them logged in:
$client->setAccessToken($site->token);
if($client->isAccessTokenExpired()) {
$NewAccessToken = json_decode($client->getAccessToken());
$client->refreshToken($NewAccessToken->refresh_token);
}
Finally, I should add that you will need to save the accessToken to the database instead of just the session to actually make it persist over different sessions. Hopefully that was obvious already.

Related

Integrating Google Sign-In into your web app

I have implemented sign-in with google for my client using google-api-php-client-2.4.0.
The implementation was quite straight forward from the documentations. I have used the following code and it is working fine. The flow is (a)set the credentials and the scopes, (b) redirect to google url, (c) google provides a code (d) get token from code (e) get the required info using the token.
require_once("../../plugins/server/google-api-php-client-2.4.0/vendor/autoload.php");
$client = new Google_Client();
$client->setClientId('*****');
$client->setClientSecret('*****');
$client->setRedirectUri("*****");
$client->addScope("email");
$client->addScope("profile");
if (isset($_GET['code']))
{
$token = $client->fetchAccessTokenWithAuthCode($_GET['code']);
$client->setAccessToken($token['access_token']);
//get profile info
$google_oauth = new Google_Service_Oauth2($client);
$google_account_info = $google_oauth->userinfo->get();
print_r($google_account_info);
}
else
{
$authUrl = $client->createAuthUrl();
header('Location: ' . $authUrl);
exit;
}
Though the above code I used is working fine, I am not sure whether this is the correct approach. I am confused because, many code samples available in internet, uses the following approach to get the token. i.e., it does not use the token directly from the code. Instead, it is again redirecting to the same page and using the token.
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
exit;
}
if ($client->getAccessToken()) {
$token_data = $client->verifyIdToken();
}
Can you help me to confirm whether my approach is fine and I can go ahead with it. Thanks.
Note: I could see from the code of the library, authenticate is deprecated method. Therefore, may be the code samples available in internet are old.

google oauth2/calendar getRefreshToken returning NULL

I'm trying to allow users to link their google calendar to my system, I've got it mostly working, and actually had it working for a while, but trying to make some modifications it's broken again :(
this page sends them to google:
require_once '../../resources/apis/google-api-php-client-2.2.1/vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('../../resources/apis/google-api-php-client-2.2.1/client_secret.json');
$client->setAccessType("offline"); // offline access
$client->setIncludeGrantedScopes(true); // incremental auth
$client->addScope(Google_Service_Calendar::CALENDAR);
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/sync/admin/apicomms/gcalmaster/syncFromGoogleCallback.php');
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Then the callback goes to here:
require_once '../../resources/apis/google-api-php-client-2.2.1/vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('../../resources/apis/google-api-php-client-2.2.1/client_secret.json');
$client->setAccessType("offline"); // offline access
$client->setIncludeGrantedScopes(true); // incremental auth
$client->addScope(Google_Service_Calendar::CALENDAR);
//$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/sync/admin/broadcast/syncFromGoogleCallback.php');
$client->authenticate($_GET['code']);
$refresh_token = $client->getRefreshToken();
var_dump($_GET);
var_dump($refresh_token);
The callback page is showing
array(2) { ["code"]=> string(89) "x/xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ["scope"]=> string(40) "https://www.googleapis.com/auth/calendar" } NULL
So it seems that the authentication is going smoothly, it's not throwing any errors...
What am I missing that is causing me to not get a refresh token? I've checked multiple times under https://myaccount.google.com/permissions to make sure my app isn't currently listed.
EDIT:
I have another script in my app which is currently working, it does the actual synchronisation, pulling the refresh token from the database, getting an access token with it, and succesfully pulling events from the calendar API. The thing that's not currently working is the 'adding' of new calendars to my app, the process of getting a refresh token from a new user
$refreshToken = $db->execute('pull refresh token from db');
require_once '../../resources/apis/google-api-php-client-2.2.1/vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('../../resources/apis/google-api-php-client-2.2.1/client_secret.json');
$client->fetchAccessTokenWithRefreshToken($refreshTokenFromDB);
$service = new Google_Service_Calendar($client);
$calendarId = 'primary';
$optParams = array(
'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);
if (count($results->getItems()) == 0) {
print "No upcoming events found.\n";
} else {
//loop through stuff
}
You are close.
So it looks like you are successful in obtaining an authorization code.
Then with your authorization code you use the:
$client->authenticate($_GET['code']);
Keep in mind this is not a token. It is an authorization code.
You now have to request a access token using the authorization code.
$accessToken = $client->getAccessToken();
It's been awhile since I've tinkered around with this, but I think that this is also your only time that you will be able to request a refresh token.
So you will want to do this line next:
$refreshToken = $client->getRefreshToken();
You will want to securely save these tokens in a json file somewhere on your system to use the next time you want to do something with this calendar.
So when you do use this again, you will use the $accessToken to establish your credentials with google. If that access token is expired you will have to use the refresh token to get a new access token. I'm pretty sure the refresh token stays constant. If not it will be sent with the new access token. Then you re-save the json file. Rinse and repeat.
UPDATED
You will use:
$client->fetchAccessTokenWithRefreshToken($refresh_token);
To obtain a new access token.

Youtube api cannot refresh access token

I previously had issue with the Google account to access Youtube's API. So i created a new fresh gmail account & managed to get it working. Not only after like One hour. I found out that Refresh Token wasn't refreshing. I don't know why. This is becoming frustrating as it seems i would have to forfeit using Youtube services any longer.
This is my code below: perhaps i'm doing something wrong.
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setScopes('https://www.googleapis.com/auth/youtube');
$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'],
FILTER_SANITIZE_URL);
$client->setRedirectUri($redirect);
$client->setAccessType('offline');
$client->setApprovalPrompt('force'); // this line is important when you revoke permission from your app, it will prompt google approval dialogue box forcefully to user to grant offline access
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
// Check if an auth token exists for the required scopes
$tokenSessionKey = 'token-' . $client->prepareScopes();
$_SESSION[$tokenSessionKey] = $manually_stored_token; //$client->getAccessToken();
if (isset($_SESSION[$tokenSessionKey])) {
$client->setAccessToken($_SESSION[$tokenSessionKey]);
}
// Check to ensure that the access token was successfully acquired.
if($client->isAccessTokenExpired()) {
$client->refreshToken($refresh_token);
if(!$client->isAccessTokenExpired()) {
// do something
} else {
// refresh access token not granted
}
} else if ($client->getAccessToken()) {
// do something
} else {
// do something
}
I checked my account https://myaccount.google.com/u/0/security, under "Sign-in & Security" for authorized access to your Google Account, I still have authorization. So i don't know why its not refreshing my Token.
When you first authorise, you are given both the access_token and refresh_token in the response.
After that, you will only get a access_token back.
The refresh_token you must save and re-use.
If for what ever reason you loose it, you must reset your authorise access.
I had this issue and had to make a dirty hack as no one could give me an answer.
Basic fix is to "un-authorise" a user and then "re-authorise" them again. As if you do not, you will never get the refresh_token back.
To test and inspect. Open your account that is being authorised.
Go into the Dashboard and find "Apps connected to your account" section.
There you will see your app and can manually remove it for testing.
However, you will need to code for this later, but is good enough for testing.

Google API Quering for Refresh Token

I've written a script that successfully queries Google for an access token using the PHP SDK.
My code,
require_once('_/libs/google/apiclient/autoload.php');
$client_id = '<MY_ID>';
$client_secret = '<MY_SECRET>';
$redirect_uri = '<REDIRECT_URL>';
// Config my apps information
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->addScope("https://mail.google.com/");
// When google redirects with code swap for access token
if (isset($_GET['code'])) {
$client->authenticate($_GET['code']);
<------------- Try to get both tokens ----------------->
$_SESSION['access_token'] = $client->getAccessToken();
$_SESSION['refresh_token'] = $client->getRefreshToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
}
Once I get the authentication code as shown above and query for the access token through getAccessToken(); it returns with the creation and expiry time.
However when I query for the refresh token through getRefreshToken(); it returns nothing when outputting it to the screen.
There was a similar question asked here
The problem seems to be letting Google know you need offline access however answers to that question aren't transferable to the PHP SDK.
Although I was using JavaScript, I just went through this exact same issue. I solved it by adding the redirect_uri parameter to the initial token request call.
Here is my SO post and my solution: Google API - Oauth 2.0 Auth token flow
To clarify the flow, to get a refresh token you actually have to make a request to get a 'code' from Google (thus my parameter 'response_type': 'code'), and then you make another call with that code to get an access token and refresh token.

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)

Categories