google oauth2/calendar getRefreshToken returning NULL - php

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.

Related

how to get Refresh token in google oauth 2.0 api with PHP

I am using to generate an access token and it's working successfully, as the access token is for a short time of 1 Hour, I want to get the Refresh Token of the user and store in DB so that I can get the access token anytime I need.
below is my code in two files.
file Oauth.php
<?php
require 'vendor/autoload.php';
// Refer to the PHP quickstart on how to setup the environment:
$client = new Google_Client();
$client->setAccessType('offline');
$client->setAuthConfigFile('client_secret.json'); //file downloaded earlier
$client->addScope("https://www.googleapis.com/auth/calendar");
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL)); //redirect user to Google
2nd File get_token.php
<?php
require 'vendor/autoload.php';
// Refer to the PHP quickstart on how to setup the environment:
$client->authenticate($_GET['code']);
$access_token = $client->getAccessToken();
$client->setAccessToken($access_token);
?>
Response I am getting like this https://www.xxxxxxxxxxxxxxxxxxx.com/google_calendar/get_token.php?code=4/0AY0e-g7ZauFJQPlzm1KsNpeuTF8S_5alcpjX8TA9LN0GVJd2cD0gAAiDPU56j2C9sVKIfg&scope=https://www.googleapis.com/auth/calendar
Thanks In advance
I did this with the following
<?php
require '../vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfig('client_secret_234rcontent.com.json');
$client->addScope('https://www.googleapis.com/auth/calendar');
$client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] .
'/google_calendar2/oauth2callback.php');
// offline access will give you both an access and refresh token so that
// your app can refresh the access token without user interaction.
$client->setAccessType('offline');
// Using "consent" ensures that your application always receives a refresh token.
// If you are not using offline access, you can omit this.
$client->setPrompt('consent');
$client->setApprovalPrompt("consent");
$client->setIncludeGrantedScopes(true); // incremental auth
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
Redirect uri code
<?php
require 'vendor/autoload.php';
$client = new Google_Client();
$client->setAuthConfigFile('client_secret_2344056t4.apps.googleusercontent.com.json');
$client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] .
'/google_calendar2/oauth2callback.php');
$client->addScope('https://www.googleapis.com/auth/calendar');
$credentials=$client->authenticate($_GET['code']);
$access_token = $client->getAccessToken();
// $refresh_token = $credentials['refresh_token'];
print_r($credentials);
When you get the access token returned from Google, what is in the response body? A refresh token is supposed to be passed back within the initial response based on OAuth 2.0 standard, and you will need to store this token somewhere safe. When you need to refresh the access token, you will need to pass in this stored refresh token with the request (maybe within the query string as a parameter), and then Google will send you back the new access token. Read through Google Documentation thoroughly as this should be explained in details!
As you could see in the response I get from Google OAuth above, the second picture is the response you are supposed to get, repeat your process of requesting the access token, and see if you get the response like what I get in the picture, and you will notice the refresh_token in the response body.

Google oauth2 access token expires in 1 hour. I want to make it 1 day

I have created a project with Google OAuth2 credentials for use with Google calendar.
However the access toke expires in every 1 hour.
Can someone please help me change the expire time to 1 day.
I have use this code to access the google calendar events:
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->setAccessType('offline');
$client->setScopes(array('https://www.googleapis.com/auth/calendar'));
if (isset($_GET['code']))
$google_oauth_code = $_GET['code'];
$client->authenticate($_GET['code']);
$_SESSION['token'] = $client->getAccessToken();
$_SESSION['last_action'] = time();
}
There are some things you need to understand about Oauth2. Access tokens are short lived they only last for one hour this is the way they work and you can not change that.
What you should be doing is storing the refresh token returned by the authentication process when you set the following.
$client->setAccessType('offline');
By using the refresh token you can request a new access token. This example might help it appears to show how to set the access token when it has expired. upload example
probably something along this lines.
$client = new Google_Client();
$client->setApplicationName(APPNAME);
$client->setClientId(CLIENTID); // client id
$client->setClientSecret(CLIENTSECRET); // client secret
$client->setRedirectUri(REDIRECT_URI); // redirect uri
$client->setApprovalPrompt('auto');
$client->setAccessType('offline'); // generates refresh token
$token = $_COOKIE['ACCESSTOKEN'];
// if token is present in cookie
if($token){
// use the same token
$client->setAccessToken($token);
}
// this line gets the new token if the cookie token was not present
// otherwise, the same cookie token
$token = $client->getAccessToken();
if($client->isAccessTokenExpired()){ // if token expired
$refreshToken = json_decode($token)->refresh_token;
// refresh the token
$client->refreshToken($refreshToken);
}
return $client;
}

refresh token with google api client not working

In my website i have an upload button for upload files to google drive via api.
Here is my code:
$auth_code = GOOGLEDRIVE_AUTH_CODE;
$access_token = GOOGLEDRIVE_ACCESS_TOKEN;
$refresh_token = GOOGLEDRIVE_REFRESH_TOKEN;
$client_id = 'Google_App_Client_ID';
$client_secret = 'Google_App_Client_Secret';
$redirect_uri = 'Redirct_Url';
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->addScope("https://www.googleapis.com/auth/drive");
$service = new Google_Service_Drive($client);
if (isset($access_token) && $access_token) {
$client->setAccessToken($access_token);
if ($client->isAccessTokenExpired()) {
$refresh_token = $client->getRefreshToken();
$client->refreshToken($refresh_token);
$access_token = $client->getAccessToken();
$co->save('GDRIVE_ACCESS_TOKEN',$access_token);
$co->save('GDRIVE_REFRESH_TOKEN',$refresh_token);
}
} else {
$authUrl = $client->createAuthUrl();
}
this line throws an error
$client->refreshToken($refresh_token);
"Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }'"
Reading up on the error message it sounds like the token refresh isn’t working all of a sudden. Like I said, this upload tool has been working fine for months.
Any Idea ?
Thanks,
Midhun
Invalid_grant
Your server’s clock is not in sync with NTP. (Solution: check the server time if its incorrect fix it. )
If its not that then there is no fix besides asking the user to authenticate again. Possible causes for the refresh token to have expired.
The user has revoked your access.
the refresh token hasn't been used in six months to request a new access token.
The refresh token limit has been exceeded. Applications can request multiple refresh tokens. For example, this is useful in situations where a user wants to install an application on multiple machines. In this case, two refresh tokens are required, one for each installation. When the number of refresh tokens exceeds the limit, older tokens become invalid. If the application attempts to use an invalidated refresh token, an invalid_grant error response is returned. The limit for each unique pair of OAuth 2.0 client and is 25 refresh tokens (note that this limit is subject to change). If the application continues to request refresh tokens for the same Client/Account pair, once the 26th token is issued, the 1st refresh token that was previously issued will become invalid. The 27th requested refresh token would invalidate the 2nd previously issued token and so on.

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 api authorization for long time

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.

Categories