如何使用Google API客户端刷新令牌?

发布于 2025-01-04 10:11:39 字数 1433 浏览 1 评论 0原文

我一直在使用 Google Analytics API (V3),但遇到了一些错误。首先,一切都设置正确并且可以与我的测试帐户一起使用。但是,当我想从另一个配置文件 ID(相同的 Google 帐户/GA 帐户)获取数据时,我收到 403 错误。奇怪的是,一些 GA 帐户的数据会返回数据,而其他帐户则会生成此错误。

我已经撤销了令牌并再次进行了身份验证,现在看来我可以从我的所有帐户中获取数据。问题解决了吗?不是。由于访问密钥即将过期,我将再次遇到同样的问题。

如果我理解正确的话,可以使用 resfreshToken 来获取新的authenticationTooken。

问题是,当我运行时:

$client->refreshToken(refresh_token_key) 

返回以下错误:

Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }'

我检查了refreshToken方法后面的代码并将请求跟踪回“apiOAuth2.php”文件。所有参数均已正确发送。 grant_type 在方法中被硬编码为“refresh_token”,因此我很难理解出了什么问题。参数数组如下所示:

Array ( [client_id] => *******-uqgau8uo1l96bd09eurdub26c9ftr2io.apps.googleusercontent.com [client_secret] => ******** [refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY [grant_type] => refresh_token )

过程如下。

$client = new apiClient();
$client->setClientId($config['oauth2_client_id']);
$client->setClientSecret($config['oauth2_client_secret']);
$client->setRedirectUri($config['oauth2_redirect_uri']);
$client->setScopes('https://www.googleapis.com/auth/analytics.readonly');
$client->setState('offline');

$client->setAccessToken($config['token']); // The access JSON object.

$client->refreshToken($config['refreshToken']); // Will return error here

这是一个错误,还是我完全误解了什么?

I've been playing around with the Google Analytics API (V3) and have run into som errors. Firstly, everything is set up correct and worked with my testing account. But when I want to grab data from another profile ID (Same Google Accont/GA Account) I get an 403 Error. The strange thing is that data from some GA accounts will return data whilst other generate this error.

I've revoked the token and authenticated one more time, and now it seems like I can grab data from all of my accounts. Problem solved? Not. As the access key will expire, I will run into the same issue again.

If I have understood things right, one could use the resfreshToken to get a new authenticationTooken.

The problem is, when I run:

$client->refreshToken(refresh_token_key) 

the following error is returned:

Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }'

I’ve checked the code behind the refreshToken method and tracked the request back to the “apiOAuth2.php” file. All parameters are sent correctly. The grant_type is hard coded to ‘refresh_token’ within the method, so it’s hard for me to understand what’s wrong. The parameter array looks like this:

Array ( [client_id] => *******-uqgau8uo1l96bd09eurdub26c9ftr2io.apps.googleusercontent.com [client_secret] => ******** [refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY [grant_type] => refresh_token )

The procedure is as follows.

$client = new apiClient();
$client->setClientId($config['oauth2_client_id']);
$client->setClientSecret($config['oauth2_client_secret']);
$client->setRedirectUri($config['oauth2_redirect_uri']);
$client->setScopes('https://www.googleapis.com/auth/analytics.readonly');
$client->setState('offline');

$client->setAccessToken($config['token']); // The access JSON object.

$client->refreshToken($config['refreshToken']); // Will return error here

Is this a bug, or have I completely misunderstood something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

过期情话 2025-01-11 10:11:39

所以我终于想出了如何做到这一点。基本思想是,您拥有第一次请求身份验证时获得的令牌。第一个令牌有一个刷新令牌。第一个原始令牌在一小时后过期。一小时后,您必须使用第一个令牌中的刷新令牌来获取新的可用令牌。您可以使用 $client->refreshToken($refreshToken) 检索新令牌。我将其称为“临时令牌”。您还需要存储此临时令牌,因为一小时后它也会过期,并注意它没有与之关联的刷新令牌。为了获取新的临时令牌,您需要使用之前使用的方法并使用第一个令牌的刷新令牌。我在下面附加了代码,这很丑陋,但我对此很陌生......

//pull token from database
$tokenquery="SELECT * FROM token WHERE type='original'";
$tokenresult = mysqli_query($cxn,$tokenquery);
if($tokenresult!=0)
{
    $tokenrow=mysqli_fetch_array($tokenresult);
    extract($tokenrow);
}
$time_created = json_decode($token)->created;
$t=time();
$timediff=$t-$time_created;
echo $timediff."<br>";
$refreshToken= json_decode($token)->refresh_token;


//start google client note:
$client = new Google_Client();
$client->setApplicationName('');
$client->setScopes(array());
$client->setClientId('');
$client->setClientSecret('');
$client->setRedirectUri('');
$client->setAccessType('offline');
$client->setDeveloperKey('');

//resets token if expired
if(($timediff>3600)&&($token!=''))
{
    echo $refreshToken."</br>";
    $refreshquery="SELECT * FROM token WHERE type='refresh'";
    $refreshresult = mysqli_query($cxn,$refreshquery);
    //if a refresh token is in there...
    if($refreshresult!=0)
    {
        $refreshrow=mysqli_fetch_array($refreshresult);
        extract($refreshrow);
        $refresh_created = json_decode($token)->created;
        $refreshtimediff=$t-$refresh_created;
        echo "Refresh Time Diff: ".$refreshtimediff."</br>";
        //if refresh token is expired
        if($refreshtimediff>3600)
        {
            $client->refreshToken($refreshToken);
        $newtoken=$client->getAccessToken();
        echo $newtoken."</br>";
        $tokenupdate="UPDATE token SET token='$newtoken' WHERE type='refresh'";
        mysqli_query($cxn,$tokenupdate);
        $token=$newtoken;
        echo "refreshed again";
        }
        //if the refresh token hasn't expired, set token as the refresh token
        else
        {
        $client->setAccessToken($token);
           echo "use refreshed token but not time yet";
        }
    }
    //if a refresh token isn't in there...
    else
    {
        $client->refreshToken($refreshToken);
        $newtoken=$client->getAccessToken();
        echo $newtoken."</br>";
        $tokenupdate="INSERT INTO token (type,token) VALUES ('refresh','$newtoken')";
        mysqli_query($cxn,$tokenupdate);
        $token=$newtoken;
        echo "refreshed for first time";
    }      
}

//if token is still good.
if(($timediff<3600)&&($token!=''))
{
    $client->setAccessToken($token);
}

$service = new Google_DfareportingService($client);

So i finally figured out how to do this. The basic idea is that you have the token you get the first time you ask for authentication. This first token has a refresh token. The first original token expires after an hour. After an hour you have to use the refresh token from the first token to get a new usable token. You use $client->refreshToken($refreshToken) to retrieve a new token. I will call this "temp token." You need to store this temp token as well because after an hour it expires as well and note it does not have a refresh token associated with it. In order to get a new temp token you need to use the method you used before and use the first token's refreshtoken. I have attached code below, which is ugly, but im new at this...

//pull token from database
$tokenquery="SELECT * FROM token WHERE type='original'";
$tokenresult = mysqli_query($cxn,$tokenquery);
if($tokenresult!=0)
{
    $tokenrow=mysqli_fetch_array($tokenresult);
    extract($tokenrow);
}
$time_created = json_decode($token)->created;
$t=time();
$timediff=$t-$time_created;
echo $timediff."<br>";
$refreshToken= json_decode($token)->refresh_token;


//start google client note:
$client = new Google_Client();
$client->setApplicationName('');
$client->setScopes(array());
$client->setClientId('');
$client->setClientSecret('');
$client->setRedirectUri('');
$client->setAccessType('offline');
$client->setDeveloperKey('');

//resets token if expired
if(($timediff>3600)&&($token!=''))
{
    echo $refreshToken."</br>";
    $refreshquery="SELECT * FROM token WHERE type='refresh'";
    $refreshresult = mysqli_query($cxn,$refreshquery);
    //if a refresh token is in there...
    if($refreshresult!=0)
    {
        $refreshrow=mysqli_fetch_array($refreshresult);
        extract($refreshrow);
        $refresh_created = json_decode($token)->created;
        $refreshtimediff=$t-$refresh_created;
        echo "Refresh Time Diff: ".$refreshtimediff."</br>";
        //if refresh token is expired
        if($refreshtimediff>3600)
        {
            $client->refreshToken($refreshToken);
        $newtoken=$client->getAccessToken();
        echo $newtoken."</br>";
        $tokenupdate="UPDATE token SET token='$newtoken' WHERE type='refresh'";
        mysqli_query($cxn,$tokenupdate);
        $token=$newtoken;
        echo "refreshed again";
        }
        //if the refresh token hasn't expired, set token as the refresh token
        else
        {
        $client->setAccessToken($token);
           echo "use refreshed token but not time yet";
        }
    }
    //if a refresh token isn't in there...
    else
    {
        $client->refreshToken($refreshToken);
        $newtoken=$client->getAccessToken();
        echo $newtoken."</br>";
        $tokenupdate="INSERT INTO token (type,token) VALUES ('refresh','$newtoken')";
        mysqli_query($cxn,$tokenupdate);
        $token=$newtoken;
        echo "refreshed for first time";
    }      
}

//if token is still good.
if(($timediff<3600)&&($token!=''))
{
    $client->setAccessToken($token);
}

$service = new Google_DfareportingService($client);
等待我真够勒 2025-01-11 10:11:39

问题出在刷新令牌上:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

当带有 '/' 的字符串被 json 编码 时,它会被 '\' 转义,因此您需要将其删除。

您的情况下的刷新令牌应该是:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

我假设您所做的是打印了 google 发回的 json 字符串,并将令牌复制并粘贴到您的代码中,因为如果您对其进行 json_decode ,那么它将正确删除 < code>'\' 给你!

The problem is in the refresh token:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

When a string with a '/' gets json encoded, It is escaped with a '\', hence you need to remove it.

The refresh token in your case should be:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

What i'm assuming you've done is that you've printed the json string which google sent back and copied and pasted the token into your code because if you json_decode it then it will correctly remove the '\' for you!

凉风有信 2025-01-11 10:11:39

这是设置令牌的代码片段,在此之前请确保访问类型应设置为离线

if (isset($_GET['code'])) {
  $client->authenticate();
  $_SESSION['access_token'] = $client->getAccessToken();
}

要刷新令牌

$google_token= json_decode($_SESSION['access_token']);
$client->refreshToken($google_token->refresh_token);

,这将刷新您的令牌,您必须在会话中更新它,您可以这样做

 $_SESSION['access_token']= $client->getAccessToken()

here is the snippet to set token, before that make sure the access type should be set to offline

if (isset($_GET['code'])) {
  $client->authenticate();
  $_SESSION['access_token'] = $client->getAccessToken();
}

To refresh token

$google_token= json_decode($_SESSION['access_token']);
$client->refreshToken($google_token->refresh_token);

this will refresh your token, you have to update it in session for that you can do

 $_SESSION['access_token']= $client->getAccessToken()
末が日狂欢 2025-01-11 10:11:39

访问类型应设置为离线state 是您为自己使用而设置的变量,而不是供 API 使用。

确保您拥有最新版本的客户端库并添加:

$client->setAccessType('offline');

有关参数的说明,请参阅形成网址

The access type should be set to offline. state is a variable you set for your own use, not the API's use.

Make sure you have the latest version of the client library and add:

$client->setAccessType('offline');

See Forming the URL for an explanation of the parameters.

五里雾 2025-01-11 10:11:39

@uri-weg 发布的答案对我有用,但由于我没有发现他的解释非常清楚,让我稍微改一下。

在第一个访问权限序列中,在回调中,当您得到在收到身份验证代码之前,您还必须保存访问令牌和刷新令牌

原因是 google api 仅在提示访问权限时才向您发送带有刷新令牌的访问令牌。下一个访问令牌将在没有任何刷新令牌的情况下发送(除非您使用 approval_prompt=force 选项)。

您第一次收到的刷新令牌将保持有效,直到用户撤销访问权限。

在 simplistic php 中,回调序列的示例如下:

// init client
// ...

$authCode = $_GET['code'];
$accessToken = $client->authenticate($authCode);
// $accessToken needs to be serialized as json
$this->saveAccessToken(json_encode($accessToken));
$this->saveRefreshToken($accessToken['refresh_token']);

稍后,在 simplistic php 中,连接序列为:

// init client
// ...

$accessToken = $this->loadAccessToken();
// setAccessToken() expects json
$client->setAccessToken($accessToken);

if ($client->isAccessTokenExpired()) {
    // reuse the same refresh token
    $client->refreshToken($this->loadRefreshToken());
    // save the new access token (which comes without any refresh token)
    $this->saveAccessToken($client->getAccessToken());
}

The answer posted by @uri-weg worked for me but as I did not find his explanations very clear, let me reword it a little.

During the first access permission sequence, in the callback, when you get to the point where you receive an authentication code, you must save the access token and the refresh token as well.

The reason is google api sends you an access token with a refresh token only when prompting for access permission. The next access tokens will be sent without any refresh token (unless you use the approval_prompt=force option).

The refresh token you received the first time stays valid until the user revokes access permission.

In simplistic php, an example of the callback sequence would be:

// init client
// ...

$authCode = $_GET['code'];
$accessToken = $client->authenticate($authCode);
// $accessToken needs to be serialized as json
$this->saveAccessToken(json_encode($accessToken));
$this->saveRefreshToken($accessToken['refresh_token']);

And later on, in simplistic php, the connection sequence would be:

// init client
// ...

$accessToken = $this->loadAccessToken();
// setAccessToken() expects json
$client->setAccessToken($accessToken);

if ($client->isAccessTokenExpired()) {
    // reuse the same refresh token
    $client->refreshToken($this->loadRefreshToken());
    // save the new access token (which comes without any refresh token)
    $this->saveAccessToken($client->getAccessToken());
}
十年不长 2025-01-11 10:11:39

这是我在项目中使用的代码,它工作正常:

public function getClient(){
    $client = new Google_Client();
    $client->setApplicationName(APPNAME);       // app name
    $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'];          // fetch from cookie

    // 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;
}

Here is the code which I am using in my project and it is working fine:

public function getClient(){
    $client = new Google_Client();
    $client->setApplicationName(APPNAME);       // app name
    $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'];          // fetch from cookie

    // 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;
}
陈独秀 2025-01-11 10:11:39

有同样的问题;我的脚本昨天有效,但由于某种奇怪的原因今天却无效了。没有变化。

显然这是因为我的系统时钟偏差了 2.5 (!!) 秒,与 NTP 同步修复了它。

另请参阅:https://code.google.com/ p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors

Had the same issue; my script that worked yesterday, for some odd reason did not today. No changes.

Apparently this was because my system clock was off by 2.5 (!!) seconds, syncing with NTP fixed it.

See also: https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors

递刀给你 2025-01-11 10:11:39

有时,刷新令牌不是通过使用 $client->setAccessType ("offline"); 生成的。

试试这个:

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 

Sometimes Refresh Token i not generated by using $client->setAccessType ("offline");.

Try this:

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 
厌味 2025-01-11 10:11:39

仅供参考:如果您有刷新令牌,则 3.0 Google Analytics API 会在访问令牌过期时自动刷新该令牌,因此您的脚本永远不需要 refreshToken

(参见auth/apiOAuth2.php中的Sign函数)

FYI: The 3.0 Google Analytics API will automatically refresh the access token if you have a refresh token when it expires so your script never needs refreshToken.

(See the Sign function in auth/apiOAuth2.php)

幼儿园老大 2025-01-11 10:11:39

您需要在初始授权请求时将访问令牌以json字符串保存到文件或数据库中,并将访问类型设置为离线 $client->setAccessType("offline")

然后在后续的授权过程中api 请求,从文件或数据库中获取访问令牌并将其传递给客户端:

$accessToken = json_decode($row['token'], true);
$client->setAccessToken($accessToken);

现在您需要检查令牌是否已过期:

if ($client->isAccessTokenExpired()) {
    // access token has expired, use the refresh token to obtain a new one
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    // save the new token to file or db
    // ...json_encode($client->getAccessToken())

fetchAccessTokenWithRefreshToken() 函数将为您完成这项工作并提供新的访问令牌,将其保存回您的文件或数据库。

You need to save the access token to file or database as a json string during the initial authorization request, and set the access type to offline $client->setAccessType("offline")

Then, during subsequent api requests, grab the access token from your file or db and pass it to the client:

$accessToken = json_decode($row['token'], true);
$client->setAccessToken($accessToken);

Now you need to check if the token has expired:

if ($client->isAccessTokenExpired()) {
    // access token has expired, use the refresh token to obtain a new one
    $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
    // save the new token to file or db
    // ...json_encode($client->getAccessToken())

The fetchAccessTokenWithRefreshToken() function will do the work for you and provide a new access token, save it back to your file or database.

月依秋水 2025-01-11 10:11:39

我将 smartcodes 的示例与当前版本的 Google API 一起使用,但该示例不起作用。我觉得他的API太过时了。

因此,我只是根据 API 示例之一编写了自己的版本...它将访问令牌、请求令牌、令牌类型、ID 令牌、过期时间和创建时间输出为字符串

如果您的客户端凭据和开发人员密钥正确,这段代码应该可以开箱即用。

<?php
// Call set_include_path() as needed to point to your client library.
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_Oauth2Service.php';
session_start();

$client = new Google_Client();
$client->setApplicationName("Get Token");
// Visit https://code.google.com/apis/console?api=plus to generate your
// oauth2_client_id, oauth2_client_secret, and to register your oauth2_redirect_uri.
$oauth2 = new Google_Oauth2Service($client);

if (isset($_GET['code'])) {
    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
    return;
}

if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
}

if (isset($_REQUEST['logout'])) {
    unset($_SESSION['token']);
    $client->revokeToken();
}
?>
<!doctype html>
<html>
    <head><meta charset="utf-8"></head>
    <body>
        <header><h1>Get Token</h1></header>
        <?php
        if ($client->getAccessToken()) {
            $_SESSION['token'] = $client->getAccessToken();
            $token = json_decode($_SESSION['token']);
            echo "Access Token = " . $token->access_token . '<br/>';
            echo "Refresh Token = " . $token->refresh_token . '<br/>';
            echo "Token type = " . $token->token_type . '<br/>';
            echo "Expires in = " . $token->expires_in . '<br/>';
            echo "ID Token = " . $token->id_token . '<br/>';
            echo "Created = " . $token->created . '<br/>';
            echo "<a class='logout' href='?logout'>Logout</a>";
        } else {
            $authUrl = $client->createAuthUrl();
            print "<a class='login' href='$authUrl'>Connect Me!</a>";
        }
        ?>
    </body>
</html>

I used the example by smartcodes with the current version of the Google API, but that one didn't work. I think his API is too outdated.

So, I just wrote my own version, based on one of the API examples... It outputs access token, request token, token type, ID token, expiration time and creation time as strings

If your client credentials and developer key are correct, this code should work out of the box.

<?php
// Call set_include_path() as needed to point to your client library.
require_once 'google-api-php-client/src/Google_Client.php';
require_once 'google-api-php-client/src/contrib/Google_Oauth2Service.php';
session_start();

$client = new Google_Client();
$client->setApplicationName("Get Token");
// Visit https://code.google.com/apis/console?api=plus to generate your
// oauth2_client_id, oauth2_client_secret, and to register your oauth2_redirect_uri.
$oauth2 = new Google_Oauth2Service($client);

if (isset($_GET['code'])) {
    $client->authenticate($_GET['code']);
    $_SESSION['token'] = $client->getAccessToken();
    $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
    header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL));
    return;
}

if (isset($_SESSION['token'])) {
    $client->setAccessToken($_SESSION['token']);
}

if (isset($_REQUEST['logout'])) {
    unset($_SESSION['token']);
    $client->revokeToken();
}
?>
<!doctype html>
<html>
    <head><meta charset="utf-8"></head>
    <body>
        <header><h1>Get Token</h1></header>
        <?php
        if ($client->getAccessToken()) {
            $_SESSION['token'] = $client->getAccessToken();
            $token = json_decode($_SESSION['token']);
            echo "Access Token = " . $token->access_token . '<br/>';
            echo "Refresh Token = " . $token->refresh_token . '<br/>';
            echo "Token type = " . $token->token_type . '<br/>';
            echo "Expires in = " . $token->expires_in . '<br/>';
            echo "ID Token = " . $token->id_token . '<br/>';
            echo "Created = " . $token->created . '<br/>';
            echo "<a class='logout' href='?logout'>Logout</a>";
        } else {
            $authUrl = $client->createAuthUrl();
            print "<a class='login' href='$authUrl'>Connect Me!</a>";
        }
        ?>
    </body>
</html>
烟燃烟灭 2025-01-11 10:11:39

自从这个问题最初发布以来,谷歌已经做了一些改变。

这是我当前工作的示例。

    public function update_token($token){

    try {

        $client = new Google_Client();
        $client->setAccessType("offline"); 
        $client->setAuthConfig(APPPATH . 'vendor' . DIRECTORY_SEPARATOR . 'google' . DIRECTORY_SEPARATOR . 'client_secrets.json');  
        $client->setIncludeGrantedScopes(true); 
        $client->addScope(Google_Service_Calendar::CALENDAR); 
        $client->setAccessToken($token);

        if ($client->isAccessTokenExpired()) {
            $refresh_token = $client->getRefreshToken();
            if(!empty($refresh_token)){
                $client->fetchAccessTokenWithRefreshToken($refresh_token);      
                $token = $client->getAccessToken();
                $token['refresh_token'] = json_decode($refresh_token);
                $token = json_encode($token);
            }
        }

        return $token;

    } catch (Exception $e) { 
        $error = json_decode($e->getMessage());
        if(isset($error->error->message)){
            log_message('error', $error->error->message);
        }
    }


}

Google has made some changes since this question was originally posted.

Here is my currently working example.

    public function update_token($token){

    try {

        $client = new Google_Client();
        $client->setAccessType("offline"); 
        $client->setAuthConfig(APPPATH . 'vendor' . DIRECTORY_SEPARATOR . 'google' . DIRECTORY_SEPARATOR . 'client_secrets.json');  
        $client->setIncludeGrantedScopes(true); 
        $client->addScope(Google_Service_Calendar::CALENDAR); 
        $client->setAccessToken($token);

        if ($client->isAccessTokenExpired()) {
            $refresh_token = $client->getRefreshToken();
            if(!empty($refresh_token)){
                $client->fetchAccessTokenWithRefreshToken($refresh_token);      
                $token = $client->getAccessToken();
                $token['refresh_token'] = json_decode($refresh_token);
                $token = json_encode($token);
            }
        }

        return $token;

    } catch (Exception $e) { 
        $error = json_decode($e->getMessage());
        if(isset($error->error->message)){
            log_message('error', $error->error->message);
        }
    }


}
风透绣罗衣 2025-01-11 10:11:39

我对 google/google-api-php-client v2.0.0-RC7 也有同样的问题
经过1个小时的搜索,我使用json_encode解决了这个问题
像这样:

    if ($client->isAccessTokenExpired()) {
        $newToken = json_decode(json_encode($client->getAccessToken()));
        $client->refreshToken($newToken->refresh_token);
        file_put_contents(storage_path('app/client_id.txt'), json_encode($client->getAccessToken()));
    }

I have a same problem with google/google-api-php-client v2.0.0-RC7
and after search for 1 hours, i solved this problem using json_encode
like this:

    if ($client->isAccessTokenExpired()) {
        $newToken = json_decode(json_encode($client->getAccessToken()));
        $client->refreshToken($newToken->refresh_token);
        file_put_contents(storage_path('app/client_id.txt'), json_encode($client->getAccessToken()));
    }
凹づ凸ル 2025-01-11 10:11:39

这在这里工作得很好,也许它可以帮助任何人:

index.php

session_start();

require_once __DIR__.'/client.php';

if(!isset($obj->error) && isset($_SESSION['access_token']) && $_SESSION['access_token'] && isset($obj->expires_in)) {
?>
<!DOCTYPE html>
<html>
<head>
<title>Google API Token Test</title>
<meta charset='utf-8' />
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
search('Music Mix 2010');
function search(q) {
    $.ajax({
        type: 'GET',
        url: 'action.php?q='+q,
        success: function(data) {
            if(data == 'refresh') location.reload();
            else $('#response').html(JSON.stringify(JSON.parse(data)));
        }
    });
}
</script>
</head>
<body>
<div id="response"></div>
</body>
</html>
<?php
}
else header('Location: '.filter_var('https://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/oauth2callback.php', FILTER_SANITIZE_URL));
?>

oauth2callback.php

require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfigFile('auth.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setRedirectUri('https://'.filter_var($_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'], FILTER_SANITIZE_URL));
$client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL);

if(isset($_GET['code']) && $_GET['code']) {
    $client->authenticate(filter_var($_GET['code'], FILTER_SANITIZE_STRING));
    $_SESSION['access_token'] = $client->getAccessToken();
    $_SESSION['refresh_token'] = $_SESSION['access_token']['refresh_token'];
    setcookie('refresh_token', $_SESSION['refresh_token'], time()+60*60*24*180, '/', filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL), true, true);
    header('Location: '.filter_var('https://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']), FILTER_SANITIZE_URL));
    exit();
}
else header('Location: '.filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL));
exit();

?>

客户端.php

// https://developers.google.com/api-client-library/php/start/installation
require_once __DIR__.'/vendor/autoload.php';

$client = new Google_Client();
$client->setAuthConfig('auth.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL);

// Delete Cookie Token
#setcookie('refresh_token', @$_SESSION['refresh_token'], time()-1, '/', filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL), true, true);

// Delete Session Token
#unset($_SESSION['refresh_token']);

if(isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
    $client->refreshToken($_SESSION['refresh_token']);
    $_SESSION['access_token'] = $client->getAccessToken();
}
elseif(isset($_COOKIE['refresh_token']) && $_COOKIE['refresh_token']) {
    $client->refreshToken($_COOKIE['refresh_token']);
    $_SESSION['access_token'] = $client->getAccessToken();
}

$url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.urlencode(@$_SESSION['access_token']['access_token']);
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, $url);
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Google API Token Test');
$json = curl_exec($curl_handle);
curl_close($curl_handle);

$obj = json_decode($json);

?>

操作.php

session_start();

require_once __DIR__.'/client.php';

if(isset($obj->error)) {
    echo 'refresh';
    exit();
}
elseif(isset($_SESSION['access_token']) && $_SESSION['access_token'] && isset($obj->expires_in) && isset($_GET['q']) && !empty($_GET['q'])) {
    $client->setAccessToken($_SESSION['access_token']);
    $service = new Google_Service_YouTube($client);
    $response = $service->search->listSearch('snippet', array('q' => filter_input(INPUT_GET, 'q', FILTER_SANITIZE_SPECIAL_CHARS), 'maxResults' => '1', 'type' => 'video'));
    echo json_encode($response['modelData']);
    exit();
}
?>

This here works very good, maybe it could help anybody:

index.php

session_start();

require_once __DIR__.'/client.php';

if(!isset($obj->error) && isset($_SESSION['access_token']) && $_SESSION['access_token'] && isset($obj->expires_in)) {
?>
<!DOCTYPE html>
<html>
<head>
<title>Google API Token Test</title>
<meta charset='utf-8' />
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
search('Music Mix 2010');
function search(q) {
    $.ajax({
        type: 'GET',
        url: 'action.php?q='+q,
        success: function(data) {
            if(data == 'refresh') location.reload();
            else $('#response').html(JSON.stringify(JSON.parse(data)));
        }
    });
}
</script>
</head>
<body>
<div id="response"></div>
</body>
</html>
<?php
}
else header('Location: '.filter_var('https://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/oauth2callback.php', FILTER_SANITIZE_URL));
?>

oauth2callback.php

require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google_Client();
$client->setAuthConfigFile('auth.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setRedirectUri('https://'.filter_var($_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'], FILTER_SANITIZE_URL));
$client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL);

if(isset($_GET['code']) && $_GET['code']) {
    $client->authenticate(filter_var($_GET['code'], FILTER_SANITIZE_STRING));
    $_SESSION['access_token'] = $client->getAccessToken();
    $_SESSION['refresh_token'] = $_SESSION['access_token']['refresh_token'];
    setcookie('refresh_token', $_SESSION['refresh_token'], time()+60*60*24*180, '/', filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL), true, true);
    header('Location: '.filter_var('https://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']), FILTER_SANITIZE_URL));
    exit();
}
else header('Location: '.filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL));
exit();

?>

client.php

// https://developers.google.com/api-client-library/php/start/installation
require_once __DIR__.'/vendor/autoload.php';

$client = new Google_Client();
$client->setAuthConfig('auth.json');
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->addScope(Google_Service_YouTube::YOUTUBE_FORCE_SSL);

// Delete Cookie Token
#setcookie('refresh_token', @$_SESSION['refresh_token'], time()-1, '/', filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL), true, true);

// Delete Session Token
#unset($_SESSION['refresh_token']);

if(isset($_SESSION['refresh_token']) && $_SESSION['refresh_token']) {
    $client->refreshToken($_SESSION['refresh_token']);
    $_SESSION['access_token'] = $client->getAccessToken();
}
elseif(isset($_COOKIE['refresh_token']) && $_COOKIE['refresh_token']) {
    $client->refreshToken($_COOKIE['refresh_token']);
    $_SESSION['access_token'] = $client->getAccessToken();
}

$url = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token='.urlencode(@$_SESSION['access_token']['access_token']);
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, $url);
curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, 2);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Google API Token Test');
$json = curl_exec($curl_handle);
curl_close($curl_handle);

$obj = json_decode($json);

?>

action.php

session_start();

require_once __DIR__.'/client.php';

if(isset($obj->error)) {
    echo 'refresh';
    exit();
}
elseif(isset($_SESSION['access_token']) && $_SESSION['access_token'] && isset($obj->expires_in) && isset($_GET['q']) && !empty($_GET['q'])) {
    $client->setAccessToken($_SESSION['access_token']);
    $service = new Google_Service_YouTube($client);
    $response = $service->search->listSearch('snippet', array('q' => filter_input(INPUT_GET, 'q', FILTER_SANITIZE_SPECIAL_CHARS), 'maxResults' => '1', 'type' => 'video'));
    echo json_encode($response['modelData']);
    exit();
}
?>
春花秋月 2025-01-11 10:11:39

我使用 google-api-php-client v2.2.2 我通过 fetchAccessTokenWithRefreshToken(); 获得一个新令牌,如果函数调用没有参数,它会返回更新的访问令牌,并且刷新的令牌不会丢失。

if ($client->getAccessToken() && $client->isAccessTokenExpired()) {
    $new_token=$client->fetchAccessTokenWithRefreshToken();
    $token_data = $client->verifyIdToken();
}    

I use google-api-php-client v2.2.2 I get a new token with fetchAccessTokenWithRefreshToken(); if function call without params, it returns an updated access token and the refreshed token is not lost.

if ($client->getAccessToken() && $client->isAccessTokenExpired()) {
    $new_token=$client->fetchAccessTokenWithRefreshToken();
    $token_data = $client->verifyIdToken();
}    
甜扑 2025-01-11 10:11:39

使用以下代码片段获取刷新令牌

    <?php

    require_once 'src/apiClient.php';
    require_once 'src/contrib/apiTasksService.php';

    $client = new apiClient();
    $client->setAccessType('offline');
    $tasksService = new apiTasksService($client);

    $auth = $client->authenticate();
    $token = $client->getAccessToken();
    // the refresh token
    $refresh_token = $token['refresh_token'];
    ?>

use the following code snippet to get your refresh token

    <?php

    require_once 'src/apiClient.php';
    require_once 'src/contrib/apiTasksService.php';

    $client = new apiClient();
    $client->setAccessType('offline');
    $tasksService = new apiTasksService($client);

    $auth = $client->authenticate();
    $token = $client->getAccessToken();
    // the refresh token
    $refresh_token = $token['refresh_token'];
    ?>
装纯掩盖桑 2025-01-11 10:11:39

根据Google 上的身份验证:OAuth2 不断返回“invalid_grant”

“您应该重复使用第一次成功身份验证后获得的访问令牌。如果您之前的令牌尚未过期,您将收到 invalid_grant 错误。将其缓存在某处,以便您可以重复使用 它。”

希望有帮助

According to Authentication on google: OAuth2 keeps returning 'invalid_grant'

"You should reuse the access token you get after the first successful authentication. You will get an invalid_grant error if your previous token has not expired yet. Cache it somewhere so you can reuse it."

hope it helps

つ可否回来 2025-01-11 10:11:39

我遇到了这个问题,我发现这是获得正确令牌的最简单、最干净的方法。

public function authenticate()
{
    $access_token = 'OLD_TOKEN';
    $refresh_token = 'OLD_TOKEN';

    if ($access_token) {
        $this->client->setAccessToken($access_token);
    }

    if ($this->client->isAccessTokenExpired()) {
         $this->client->refreshToken($refresh_token);
    }
}

我有 client 作为类的属性,这就是我使用 $this->client 的原因。

I got into this issue and I found this to be the simplest and cleanest way to get proper token.

public function authenticate()
{
    $access_token = 'OLD_TOKEN';
    $refresh_token = 'OLD_TOKEN';

    if ($access_token) {
        $this->client->setAccessToken($access_token);
    }

    if ($this->client->isAccessTokenExpired()) {
         $this->client->refreshToken($refresh_token);
    }
}

I have client as property on the class that's why I am using $this->client.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文