Google API Client “refresh token must be passed in or set as part of setAccessToken”

后端 未结 9 1366
Happy的楠姐
Happy的楠姐 2020-12-05 07:55

I am currently facing a very strange problem, indeed I\'ve been following this very same guide (https://developers.google.com/google-apps/calendar/quickstart/php) from Googl

相关标签:
9条回答
  • 2020-12-05 08:27

    just some update for anyone having trouble with this message, mostly it's because only first command fetchAccessTokenWithAuthCode() generates credencials that contains the refresh token (technically forever valid - no 2 hours validity if you dont revoke it). When you get the new one it replaces the original one yet it does not contains the refresh token that it needs so next time you need to update the token, it will crash. This can be easily fixed by replacing the refresh function to for example this:

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

    Now everytime you update the access token your refresh token is passed down too.

    0 讨论(0)
  • 2020-12-05 08:30

    I have faced the same issue with new google api library. Search for solution brought the following link: RefreshToken Not getting send back after I get new token google sheets API

    Based on that information, I have modified the quickstart code part to fit my needs. After first authorization with Google I have obtained drive-php-quickstart.json which contains refresh_token that expires in 3600 seconds or one hour. The refresh token is issued only once, so if it is lost, then re-authorization is required. So, that to have it always in drive-php-quickstart.json I have done following:

    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
    // save refresh token to some variable
    $refreshTokenSaved = $client->getRefreshToken(); 
    
    // update access token
    $client->fetchAccessTokenWithRefreshToken($refreshTokenSaved); 
    
    // pass access token to some variable
    $accessTokenUpdated = $client->getAccessToken();
    
    // append refresh token
    $accessTokenUpdated['refresh_token'] = $refreshTokenSaved;
    
    // save to file
    file_put_contents($credentialsPath, json_encode($accessTokenUpdated)); 
    }
    
    0 讨论(0)
  • 2020-12-05 08:32

    So After some time vieweing this code:

    // Exchange authorization code for an access token.
    // "refresh_token" is returned along with the access token
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
    $client->setAccessToken($accessToken);
    
    
    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
        $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
    }
    

    all was needed is this change:

    // Exchange authorization code for an access token.
    // "refresh_token" is returned along with the access token
    $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
    $client->setAccessToken($accessToken);
    
    
    // Refresh the token if it's expired.
    if ($client->isAccessTokenExpired()) {
        $client->fetchAccessTokenWithRefreshToken($accessToken);
        file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
    }
    

    since this function $client->getRefreshToken() returns null, and if you provide the $accessToken directly, it will work just fine and update your file, hope it resolves somebody issue.

    0 讨论(0)
  • 2020-12-05 08:35

    You need to serialize the accestoken when you write it to the credentialsPath.

     // Exchange authorization code for an access token.
        $accessToken = $client->authenticate($authCode);
    
        // Store the credentials to disk.
        if(!file_exists(dirname($credentialsPath))) {
            mkdir(dirname($credentialsPath), 0700, true);
        }
        $serArray = serialize($accessToken);
        file_put_contents($credentialsPath, $serArray);
        printf("Credentials saved to %s\n", $credentialsPath);
    

    And when you read from the file you need to unserialize it.

    if (file_exists($credentialsPath)) {
        $unserArray =  file_get_contents($credentialsPath);
        $accessToken = unserialize($unserArray);
    
    }
    

    Full function

    function getClient() {
        $client = new Google_Client();
        // Set to name/location of your client_secrets.json file.
        $client->setAuthConfigFile('client_secret.json');
        // Set to valid redirect URI for your project.
        $client->setRedirectUri('http://localhost');
        $client->setApprovalPrompt('force');
    
        $client->addScope(Google_Service_YouTube::YOUTUBE_READONLY);
        $client->setAccessType('offline');
    
        // Load previously authorized credentials from a file.
        $credentialsPath = expandHomeDirectory(CREDENTIALS_PATH);
    
    
        if (file_exists($credentialsPath)) {
            $unserArray =  file_get_contents($credentialsPath);
            $accessToken = unserialize($unserArray);
    
        } else {
            // Request authorization from the user.
            $authUrl = $client->createAuthUrl();
            printf("Open the following link in your browser:\n%s\n", $authUrl);
            print 'Enter verification code: ';
            $authCode = trim(fgets(STDIN));
    
            // Exchange authorization code for an access token.
            $accessToken = $client->authenticate($authCode);
    
            // Store the credentials to disk.
            if(!file_exists(dirname($credentialsPath))) {
                mkdir(dirname($credentialsPath), 0700, true);
            }
            $serArray = serialize($accessToken);
            file_put_contents($credentialsPath, $serArray);
            printf("Credentials saved to %s\n", $credentialsPath);
        }
    
        $client->setAccessToken($accessToken);
    
        // Refresh the token if it's expired.
        if ($client->isAccessTokenExpired()) {
            $client->refreshToken($client->getRefreshToken());
            file_put_contents($credentialsPath, $client->getAccessToken());
        }
        return $client;
    }
    
    0 讨论(0)
  • 2020-12-05 08:42

    I got the same problem recently and i solved it with this.

    <?php
     $client->setRedirectUri($this->_redirectURI);
     $client->setAccessType('offline');
     $client->setApprovalPrompt('force');
    

    I explain ..... Refresh token is not returned because we didnt force the approvalPrompt. The offline mode is not enought. We must force the approvalPrompt. Also the redirectURI must be set before these two options. It worked for me.

    This is my full function

    <?php
         private function getClient()
         {
            $client = new Google_Client();
            $client->setApplicationName($this->projectName);
            $client->setScopes(SCOPES);
            $client->setAuthConfig($this->jsonKeyFilePath);
            $client->setRedirectUri($this->redirectUri);
            $client->setAccessType('offline');
            $client->setApprovalPrompt('force');
    
           // Load previously authorized credentials from a file.
           if (file_exists($this->tokenFile)) {
             $accessToken = json_decode(file_get_contents($this->tokenFile), 
             true);
          } else {
            // Request authorization from the user.
            $authUrl = $client->createAuthUrl();
            header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL));
    
            if (isset($_GET['code'])) {
                $authCode = $_GET['code'];
                // Exchange authorization code for an access token.
                $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
                header('Location: ' . filter_var($this->redirectUri, 
                FILTER_SANITIZE_URL));
                if(!file_exists(dirname($this->tokenFile))) {
                    mkdir(dirname($this->tokenFile), 0700, true);
                }
    
                file_put_contents($this->tokenFile, json_encode($accessToken));
            }else{
                exit('No code found');
            }
        }
        $client->setAccessToken($accessToken);
    
        // Refresh the token if it's expired.
        if ($client->isAccessTokenExpired()) {
    
            // save refresh token to some variable
            $refreshTokenSaved = $client->getRefreshToken();
    
            // update access token
            $client->fetchAccessTokenWithRefreshToken($refreshTokenSaved);
    
            // pass access token to some variable
            $accessTokenUpdated = $client->getAccessToken();
    
            // append refresh token
            $accessTokenUpdated['refresh_token'] = $refreshTokenSaved;
    
            //Set the new acces token
            $accessToken = $refreshTokenSaved;
            $client->setAccessToken($accessToken);
    
            // save to file
            file_put_contents($this->tokenFile, 
           json_encode($accessTokenUpdated));
        }
        return $client;
    }
    
    0 讨论(0)
  • 2020-12-05 08:42

    My advice is save refresh token to .json immediately after get access token and if access token expired use refresh token.

    In my projects work this way:

    public static function getClient()
    {
        $client = new Google_Client();
        $client->setApplicationName('JhvInformationTable');
        $client->setScopes(Google_Service_Calendar::CALENDAR_READONLY);
        $client->setAuthConfig('credentials.json');
        $client->setAccessType('offline');
    
        // Load previously authorized credentials from a file.
        $credentialsPath = 'token.json';
        $credentialsPath2 = 'refreshToken.json';
        if (file_exists($credentialsPath)) {
            $accessToken = json_decode(file_get_contents($credentialsPath), true);
        } else {
            // Request authorization from the user.
            $authUrl = $client->createAuthUrl();
            //printf("Open the following link in your browser:\n%s\n", $authUrl);
            //print 'Enter verification code: ';
            $authCode = trim(fgets(STDIN));
    
            //echo "<script> location.href='".$authUrl."'; </script>";
            //exit;
    
            $authCode ='********To get code, please uncomment the code above********';
    
            // Exchange authorization code for an access token.
            $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
            $refreshToken = $client->getRefreshToken();
    
            // Check to see if there was an error.
            if (array_key_exists('error', $accessToken)) {
                throw new Exception(join(', ', $accessToken));
            }
    
            // Store the credentials to disk.
            if (!file_exists(dirname($credentialsPath))) {
                mkdir(dirname($credentialsPath), 0700, true);
            }
            file_put_contents($credentialsPath, json_encode($accessToken));
            file_put_contents($credentialsPath2, json_encode($refreshToken));
            printf("Credentials saved to %s\n", $credentialsPath);
        }
        $client->setAccessToken($accessToken);
    
        // Refresh the token if it's expired.
        if ($client->isAccessTokenExpired()) {
            $refreshToken = json_decode(file_get_contents($credentialsPath2), true);
            $client->fetchAccessTokenWithRefreshToken($refreshToken);
            file_put_contents($credentialsPath, json_encode($client->getAccessToken()));
        }
        return $client;
    }
    
    0 讨论(0)
提交回复
热议问题