1

So I've literally copied the code from the Google example (https://developers.google.com/google-apps/calendar/quickstart/php) and followed its instructions as best as I can, and then my calendar worked quite well. But I've come in today and realized that it stopped working, and I can't figure out what's wrong.

I believe the root of my problem is this line :

$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());

since that line gives me this error

Uncaught LogicException: refresh token must be passed in or set as part of setAccessToken

There are similar questions (Get refresh token google api, Not receiving Google OAuth refresh token) But I don't seem to be able to solve my problem with their answers.

Another note; $client->getRefreshToken() seems to be returning null when I test it, which is why I think $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); is failing.


So this is the piece of code directly from the example that is in question

// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}

That piece of code gives me errors because $client->getRefreshToken() is null, but I was under the assumption that I needed to use the refresh token to get a new token, which I can't do if there is no refresh token?


Also note, that this is already being set at the beginning of the calls

$client->setAccessType('offline');
$client->setApprovalPrompt('force');
Community
  • 1
  • 1
Brian Leishman
  • 8,155
  • 11
  • 57
  • 93

2 Answers2

1

In your code

// Refresh the token if it's expired.
if ($client->isAccessTokenExpired()) {
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
}

there is one important thing missing:

before you get your refresh token, you should check first if it exists, and if not - create it first. This is what it should look like:

// Refresh the access token if it's expired.
if ($client->isAccessTokenExpired()) 
 {
    // Refresh the refresh token if possible, else fetch a new one.
    if ($client->getRefreshToken()) // checks if the refresh token exists
    {
        $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken()); //creates an access token, provided that a refresh token exists
     } else // If the refresh token does not exist, you have to create it first 
     {
        $authUrl = $client->createAuthUrl();
        printf("Open the following link in your browser:\n%s\n", $authUrl); // you will be prompted to follow the authentification link and perform the authentification
        print 'Enter verification code: '; // subsequently you will receive a verification code that you need to create a new token
        $authCode = trim(fgets(STDIN));

Btw: If your refresh token already exists - it should be in the token.json file under your token path, however it could be invalid if you have changed the scopes after it was created. In this case, you should erase the token.json file, so that a new one can be generated.

ziganotschka
  • 25,866
  • 2
  • 16
  • 33
0

Please note that access tokens have a limited lifetime and when it happens, this causes your Calendar to stop working. So, as suggested in Token expiration, you should write in your code to anticipate the possibility that a granted token might no longer work. This is where, refresh tokens becomes very useful for it allows your application to obtain new access tokens without going through the Authorization process again.

To request a refresh token, add access_type=offline to your authentication request. However, this GitHub post suggests that you could obtain the refresh token by providing the parameters access_type=offline&approval_prompt=force in your request.

For more helpful tips, I think the following links will be beneficial:

Community
  • 1
  • 1
Teyam
  • 7,686
  • 3
  • 15
  • 22
  • 1
    Yep, I've already set those flags, since they're in the example. And I know that it's supposed to be refreshed, that's what the lines commented as `Refresh the token if it's expired.` are supposed to be doing but I'm not getting a new key back at all – Brian Leishman Sep 20 '16 at 12:58
  • I've added a part to my question to hopefully further clarify – Brian Leishman Sep 20 '16 at 13:17
  • To clarify the confusing behaviour here, Google returns a refresh token as part of the response to your first request. If you don't save it then, for any subsequent request, the "approval_prompt=force" is required to get a refresh token, as it is otherwise not returned. – Brian C Dec 12 '19 at 05:58