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

我一直在玩Google Analytics API(V3),并且遇到了som错误。 首先,一切都设置正确,并与我的testing帐户。 但是,当我想从另一个configuration文件ID(相同谷歌Accont / GA帐户)抓取数据时,我得到一个403错误。 奇怪的是,一些GA帐户的数据将返回数据,而其他产生这个错误。

我已经撤销了令牌并且再次validation了一次,现在好像我可以从我的所有帐户中获取数据。 问题解决了? 不。 随着访问密钥到期,我将再次遇到同样的问题。

如果我理解正确的话,可以使用resfreshToken来获得一个新的身份validation。

问题是,当我运行:

$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 

这是一个错误,还是我完全误解了一些东西?

所以我终于想出了如何做到这一点。 基本的想法是,你有第一次要求authentication的令牌。 这第一个标记有一个刷新标记。 第一个原始令牌在一个小时后过期。 一小时之后,您必须使用第一个令牌中的刷新令牌来获取新的可用令牌。 您可以使用$client->refreshToken($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); 

问题出在刷新标记中:

 [refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY 

当一个带有'/'的string被json encoded ,它会被一个'\'转义,所以你需要删除它。

您的案例中的刷新令牌应该是:

 1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY 

我假设你已经做的是,你已经打印了谷歌发回的JSONstring,复制并粘贴令牌到你的代码,因为如果你json_decode它,那么它会正确地删除'\'为你!

访问types应设置为offlinestate是一个你自己设定的variables,而不是API的使用。

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

 $client->setAccessType('offline'); 

请参阅形成URL以获取参数的解释。

这里是设置令牌的片段,在此之前确保访问types应设置为离线

 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() 

@ uri-weg发布的答案为我工作,但由于我没有find他的解释非常清楚,让我稍微重新说一下。

在第一个访问权限序列期间,在callback中,当您到达接收authentication码的位置时,您还必须保存访问令牌和刷新令牌

原因是谷歌API向您发送刷新令牌的访问令牌只有当提示访问权限。 下一个访问令牌将不带任何刷新标记发送(除非使用approval_prompt=force选项)。

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

在简单的PHP中,callback序列的一个例子是:

 // 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']); 

后来,在简单的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 refrsh token) $this->saveAccessToken($client->getAccessToken()); } 

有同样的问题; 我的脚本昨天工作,由于一些奇怪的原因没有今天。 没有变化。

显然这是因为我的系统时钟已经closures了2.5(!!)秒,与NTP同步固定它。

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

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

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

仅供参考:3.0谷歌分析API将自动刷新访问令牌,如果你有一个刷新令牌过期,所以你的脚本永远不需要refreshToken

(请参阅auth/apiOAuth2.phpSign函数)

我通过智能代码使用了当前版本的Google API的示例,但那不起作用。 我认为他的API太过时了。

所以,我只是写了一个基于其中一个API例子的自己的版本…它输出访问令牌,请求令牌,令牌types,ID令牌,过期时间和创build时间作为string

如果您的客户端凭据和开发人员密钥正确,则此代码应该可以直接使用。

 <?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> 

我有同样的问题谷歌/谷歌的API – 客户端V2.0.0 RC7和search1小时后,我解决了这个问题,使用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())); } 

有时刷新令牌我没有通过使用$client->setAccessType ("offline");

尝试这个:

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

据谷歌身份validation:OAuth2不断返回'invalid_grant'

“你应该重新使用第一次成功的身份validation后获得的访问令牌,如果你以前的令牌没有过期,你将会得到一个invalid_grant错误,将它caching在某个地方,以便重用它。

希望它有帮助

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

的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(); } ?> 

使用下面的代码片段来获取您的刷新标记

  <?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']; ?>