Как обновить токен с клиентом API Google?

Я играл с API Google Analytics (V3) и сталкивался с ошибками som. Во-первых, все настроено правильно и работает с моей тестовой учетной записью. Но когда я хочу захватить данные из другого идентификатора профиля (тот же аккаунт Google Accont / GA), я получаю ошибку 403. Странно, что данные из некоторых учетных записей GA будут возвращать данные, в то время как другие генерируют эту ошибку.

Я отозвал токен и аутентифицировался еще раз, и теперь кажется, что я могу захватить данные со всех моих учетных записей. Задача решена? Не. По мере того, как ключ доступа истечет, я снова столкнусь с тем же вопросом.

Если бы я понял все правильно, можно было бы использовать resfreshToken для получения новой аутентификацииTooken.

Проблема в том, что когда я запускаю:

$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 

Является ли это ошибкой, или я совершенно ничего не понял?

Поэтому я наконец понял, как это сделать. Основная идея заключается в том, что у вас есть маркер, который вы получаете при первом запросе аутентификации. Этот первый токен имеет токен обновления. Первый оригинальный токен истекает через час. Через час вам нужно использовать токен обновления с первого токена, чтобы получить новый полезный токен. Вы используете $client->refreshToken($refreshToken) чтобы получить новый токен. Я назову этот «токен темпа». Вам нужно также сохранить этот токен темпа, потому что через час он истекает, а также отмечает, что у него нет токена обновления, связанного с ним. Чтобы получить новый токен temp, вам нужно использовать метод, который вы использовали ранее, и использовать 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 

Когда строка с '/' получает json encoded , она экранируется с помощью '\' , поэтому вам нужно ее удалить.

Токен обновления в вашем случае должен быть:

 1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY 

То, что я предполагаю, что вы сделали, это то, что вы напечатали строку json, которую google отправил назад и скопировал, и вставил токен в ваш код, потому что если вы json_decode то он правильно удалит '\' для вас!

Тип доступа должен быть offline . state – это переменная, которую вы устанавливаете для собственного использования, а не для использования API.

Убедитесь, что у вас установлена последняя версия клиентской библиотеки и добавьте:

 $client->setAccessType('offline'); 

См. Формирование URL-адреса для объяснения параметров.

вот фрагмент, чтобы установить токен, прежде чем убедитесь, что тип доступа должен быть установлен в автономный

 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, работал для меня, но, поскольку я не нашел его объяснений очень ясным, позвольте мне немного изменить его.

Во время первой последовательности прав доступа в обратном вызове, когда вы добираетесь до точки, в которой вы получаете код аутентификации, вы должны также сохранить токен доступа и токен обновления .

Причина заключается в том, что google api отправляет вам токен доступа с токеном обновления только при запросе разрешения на доступ. Следующие токены доступа будут отправляться без токена обновления (если вы не используете параметр approval_prompt=force ).

Обновленный токен, который вы получили в первый раз, действует до тех пор, пока пользователь не аннулирует доступ.

В упрощенном 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']); 

И позже, в упрощенном 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()); } 

Имел такой же вопрос; мой скрипт, который работал вчера, по какой-то странной причине не был сегодня. Без изменений.

По-видимому, это было из-за того, что мои системные часы были отключены на 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; } 

FYI: 3.0 API Google Analytics автоматически обновит токен доступа, если у вас есть токен обновления, когда он истекает, поэтому ваш скрипт никогда не нуждается в refreshToken .

(См. Функцию Sign в auth/apiOAuth2.php )

Я использовал этот пример с помощью смарткодов с текущей версией API Google, но этот не работал. Я думаю, что его 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> с <?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> 

У меня такая же проблема с 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())); } 

Иногда обновлять токен я не генерируется с помощью $client->setAccessType ("offline"); ,

Попробуй это:

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

Согласно аутентификации в google: OAuth2 продолжает возвращать 'invalid_grant'

«Вы должны повторно использовать токен доступа, который вы получите после первой успешной проверки подлинности. Вы получите ошибку invalid_grant, если ваш предыдущий токен еще не истек. Загрузите его где-нибудь, чтобы вы могли его повторно использовать».

Надеюсь, поможет

Это здесь работает очень хорошо, может быть, это может помочь кому угодно:

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