While running this example
https://developers.google.com/sheets/quickstart/php
I noticed after the AccessToken expires it uses refresh_token to fetch a new token however it returns creds without the refresh_token included. As a result, subsequent attempts to fetch a new accessToken (after the expire) fail because the refresh_token is not saved and thus not able to be passed back to fetchAccessTokenWithRefreshToken again.
Should this be reinserted back into the creds?
/vendor/google/apiclient/src/Google/Client.php 2016-09-27 15:13:43.178769896 -0700
@@ -271,6 +271,7 @@
$creds = $auth->fetchAuthToken($httpHandler);
if ($creds && isset($creds['access_token'])) {
$creds['created'] = time();
+ $creds['refresh_token'] = $refreshToken;
$this->setAccessToken($creds);
}
Just ended up here as a result of a search after finding the same behavior.
I was also seeing the same problem with offline access.
However it looks like we actually needed to store the original refresh_token given to us at first authorisation to be reused later on. I had assumed a new refresh_token would be generated so kept overwriting the returned access token data stored in the DB.
I am now simply appending the original refresh_token back into the access token array and storing it again.
@LetterboxDelivery is right - the refresh token is only delivered the first time an application is authorized.
We could add the refresh token back to the in-memory access token, but this is not a guaranteed fix, as the access token can be cached at the auth level. I do think it would be an improvement, however.
The important point for me is, I had setup access to the Calendar API back in January, and downloaded this library, and that version of the library, when the access token has expired, renews and passes back both the new token and the (original) refresh token, for saving / caching the file off for use after the next expiration, using:
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->refreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, $client->getAccessToken());
}
Has this behavior intentionally changed in this version? The current version calls (by way of example in the quick start):
// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}
Which no longer includes the refresh token. Meaning, doing nothing different using the "same" library, under the new scripts, you can only maintain access for 2 hours (original token, followed by refresh token), but when the third attempt occurs, since the refresh token is no longer present, you're DOA.
I certainly understand how to extract and save off the refresh token manually for later use, but one did not have to do this manually using the library a short time ago, so the behavior has changed (intentional?).
Rolanyang's suggestion makes sense from my perspective and resolves the "issue".
Perhaps at some point in the past, the refresh token was being returned but is no longer now. I wonder if there is logic on the server side that might have stopped the return of refresh tokens if the oauth permissions were revoked. If that is the case and, in the future, the server does start returning refresh tokens again, then this might be better:
if (!isset($creds['refresh_token']) {
$creds['refresh_token'] = $refreshToken;
}
In case the behavior was intentionally changed, then the documentation/quickstart needs to be updated accordingly, otherwise everybody will be induced to this mistake...
Be sure to add $client->setAccessType('offline');. I've also came across this 'error'
I have $client->setAccessType('offline'); doesn't make the refresh token to be returned, at least not for me.
I too am having the same issue I think it is definitely a server side issue
I am facing the same problem the problem here is that the call for refreshing token using the refresh token doesn't set the refresh token and sends only the access token. Complete description written in #1102
Seems that the library is not considering the accessType when refreshing the token.
Thanks,
Sadashiv.
I am also facing the same issue , 'refresh token must be passed in or set as part of setAccessToken'
Not sure what wrong /how to resolve it .
Has anyone found the solution . it was working good for first time , after 6 hrs its giving me the above error
Everyone please take a look at #1121
Besides
$client->setAccessType('offline');
Need to include force prompt to Google return the refresh token:
$client->setApprovalPrompt('force');
Works for me.
The initial oauth sequence must include the line of code below -
$client->setApprovalPrompt('force');
Without this, when accessToken expires, there will be no refreshToken available - the getRefreshToken() function will return null, which in turn causes fetchAccessTokenWithRefreshToken to fail.
I don't know if this setApprovalPrompt setting is a legitimate requirement of what I'm trying to do, or relates to an issue elsewhere within the Google Client PHP API. I just know it fixes the problem of the various quickstart.php samples published by Google that fail to refresh expired access tokens.
It looks like a member of our great community answered your questions. Thanks Community! Please feel free to reopen if you have any more questions.
As an issue, isn't this still open? getRefreshToken() should, well, get a refresh token, yes?
If the API is behaving as intended (which would require some explanation), then the code on the Google Sample for PHP needs to be amended.
After set
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
Don't forget to delete your previous credential token.
This was it for me. The refresh token was returned the very first time I authorized my account on my app. Subsequent re-authorizations without revoking the existing token first only gave me the access token. So I added a small piece of code to check for refresh tokens on client authorizations. If it is empty, I revoke the current access token and tell the user to re-authorize.
I was also seeing the same problem with offline access.
However it looks like we actually needed to store the original refresh_token given to us at first authorisation to be reused later on. I had assumed a new refresh_token would be generated so kept overwriting the returned access token data stored in the DB.
I am now simply appending the original refresh_token back into the access token array and storing it again.
Most helpful comment
Besides
$client->setAccessType('offline');Need to include force prompt to Google return the refresh token:
$client->setApprovalPrompt('force');Works for me.