refresh token with google api client not working - php

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.

Related

Youtube Google API Caught Google service Exception 0 message is refresh token must be passed in or set as part of setAccessTokenStack

I am currently facing this problem: once I authorized youtube to access my account and after saving the token in a file called "token.txt," everything runs smoothly until the token expires. My script is not able to refresh the token.
Error
Caught Google service Exception 0 message is refresh token must be
passed in or set as part of setAccessTokenStack trace is #0
/home/omqoygue/contest.diamante.live/vendor/google/apiclient/src/Client.php(321):
Google\Client->fetchAccessTokenWithRefreshToken(NULL)
#1 /home/omqoygue/contest.diamante.live/upload.php(40): Google\Client->refreshToken(NULL)
#2 /home/omqoygue/contest.diamante.live/index.php(18): include('/home/omqoygue/...')
#3 {main}
This is where the token is created and stored in a file.
if (isset($_SESSION['token'])) {
$client->setAccessToken($_SESSION['token']);
$token = json_encode($_SESSION['token']);
file_put_contents('token.txt', $token);
foreach ($_SESSION['token'] as $key => $value) {
echo '<code>'.$key.":".$value."<br>".'</code>';
}
}
This is the part where the token validity is checked. If it has expired, it should be updated, but this does not happen.
$token = file_get_contents('token.txt');
try {
// Client init
$client = new Google_Client();
$client->setApplicationName($application_name);
$client->setClientId($client_id);
$client->setAccessType('offline');
$client->setAccessToken($token);
$client->setScopes($scope);
$client->setClientSecret($client_secret);
if ($client->getAccessToken()) {
/**
* Check to see if our access token has expired.
* If so, get a new one and save it to file for future use.
*/
if ($client->isAccessTokenExpired()) {
$newToken = json_decode($client->getAccessToken());
$client->refreshToken($newToken->refreshToken);
file_put_contents('token.txt', $client->getAccessToken());
}
}
}
When the token expires, I have to give permission again to youtube to access my account. I hope someone can help me, I have already checked the other posts on the subject, but they are obsolete.
If your refresh token is expired then you will need to authorize the app again there is no way around that. The easiest way to do that with your code is to delete 'token.txt' it should prompt you to authorize the app again.
Once your app is set to production instead of testing in Google developer console your token will stop expiring every seven days.

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.

PHP Google API Refresh Token

Having a problem with the refreshToken procedure with Google API, upon an expired token is experienced the refreshToken doesn't get an AccessToken. I've already saved the refresh token to the db at this point.
$client = new Google_Client();
$client->setApplicationName("APP NAME");
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setAccessType('offline');
$client->setScopes(array('https://www.googleapis.com/auth/calendar'));
$client->setAccessToken( json_encode($access_token_from_db) );
if ( $client->isAccessTokenExpired() ) :
$client->refreshToken($refresh_token_from_db);
$new_access_token = $client->getAccessToken();
print_r($access_token);
//save to db -- but this fails
endif;
After running this the new access token is still empty. Even if I setAccessToken to the now expired token prior to checking expiration the same problem persists.
There doesn't seem to be a straight forward example on a state after a refreshToken has already been saved.
In my application we would cron job to send updates to a user's calendar based on actions (if necessary to understand the application purpose).
The reason this answer doesn't seem correct to me:
How to refresh token with Google API client?
is because it's not using the $client->isAccessTokenExpired() method, plus isn't a clean solution, the script should be very minimal and small to complete the task. In theory:
setAccessToken to the one given on authorization
if expired (via function), use the refresh to access a new token
save the token and continue
While the above example had similar functions it's a 2013 answer and may work but isn't the best way to do this I believe.
My failure was because I messed up my own clientID, but I'm posting this script here anyways because it took me forever to find the correct answer that was small, efficient and effective (the below is strictly after a token and refresh have been already saved to your db):
$client = new Google_Client();
$client->setApplicationName('APP NAME');
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setAccessType('offline');
$client->setScopes(array('https://www.googleapis.com/auth/calendar'));
// my app is for google calendar.
$access_token_from_db = 'XXXXXX';
$refresh_token_from_db = 'XXXXX';
$_tokenArray['access_token'] = $access_token_from_db
$client->setAccessToken( $_tokenArray );
//check if token expired:
if ( $client->isAccessTokenExpired() ) :
$client->refreshToken($refresh_token_from_db);
$new_access_token = $client->getAccessToken();
//now save your new access token to your db
endif;

How do I refresh OAuth token?

I am using Google Drive API and authenticating using OAuth token using PHP program. For my test program I went to OAuth url manually and created a token. Then, I used it in the program and saved it to the file. From next time onwards the token is loaded from file and the program is able to access Google Drive. However, since the token would only be valid for 1 hr, after that I get the error since the token it retrieves from the file won't be valid anymore. I am not clear on how I can refresh the token so that its not required to manually obtain a new token.
Following is my code -
$client = new Google_Client();
$client->setClientId( CLIENT_ID );
$client->setClientSecret( CLIENT_SECRET );
$client->setRedirectUri( REDIRECT_URIS );
$client->setScopes($SCOPES);
$client->setAccessType('offline');
$client->setAuthConfigFile(CLIENT_SECRET_PATH);
If the cred file exist, I pull the token from that file else I would be fetching it. For now, the first time token I am setting manually -
if (file_exists(CREDENTIALS_PATH)) {
$accessToken = file_get_contents(CREDENTIALS_PATH);
} else {
$authCode = 'My Auth Code';
$accessToken = $client->authenticate($authCode);
}
file_put_contents(CREDENTIALS_PATH, $accessToken);
$client->setAccessToken($accessToken);
Now, if the token is expired I need to refresh the token automatically.
if ($client->isAccessTokenExpired()) {
//This is where I am running in trouble.
}
How do I achieve it? The target is to perform OAuth authentication and execute Google Drive API without any manual intervention.
Thank you for the help!
Looks like I found the answer.
I used the OAuth url for the first time access to include the parameter prompt=consent. So this generated the refresh-token that was saved in the file. After that, following addition to code did the trick -
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
file_put_contents(CREDENTIALS_PATH, $client->getAccessToken());
}
After this the token is no longer expiring after an hour.

Google PHP SDK - not getting refresh token

I am trying to get a refresh token for the Google API's, using the PHP SDK. I am authenticating the user with Javascript, retrieving a code, and exchanging it for an access_token server side, but this doesn't grant me an access token. What am I doing wrong? Here is the code I use:
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->addScope('https://www.googleapis.com/auth/plus.me');
$client->addScope('https://www.google.com/m8/feeds');
$client->setRedirectUri('postmessage');
$client->setAccessType('offline');
if (isset($_REQUEST['code'])) {
$client->authenticate($_REQUEST['code']);
if ($client->getAccessToken()) {
$_SESSION['access_token'] = $client->getAccessToken();
$token_data = $client->verifyIdToken()->getAttributes();
$result['data']=$token_data;
$result['access_token']=json_decode($_SESSION['access_token']);
}
}
debug($result); //my own function, var_dumps the content of an array
Here is the result of the array:
$result['access_token'] contains:
access_token: TOKEN
created: 1434380576
expires_in: 3594
id_token: IDTOKEN
token_type:"Bearer"
If I am not mistaken the first access token should also contain the refresh token, what am I doing wrong?
First check the settings in the developer console of Google to see if your RedirectUri is the same and that the API is activated (although if you already got that .json, then I assume it is.
You have to go through the Google Auth Prompt Screen at least 1 time to get a refresh token in your .json, and if your RedirectUri is taking you nowhere, you won't be able to get your refresh token or even the access validated.
You can also try a service account if you're doing small file transactions and don't need a user validation for the process of your script. Good Luck.
The problem was that I had to specify that I want offline access in the authentication process, the client side... The Google API's are horribly documented!!!

Categories