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

92

Я играл с Google Analytics API (V3) и сталкивался с ошибками. Во-первых, все настроено правильно и работает с моей тестовой учетной записью. Но когда я хочу получить данные из другого идентификатора профиля (та же учетная запись Google Accont / 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

Это ошибка, или я что-то совершенно не понял?

seorch.me
источник
Не знаю, ошибка это или что-то в этом роде, но сейчас я обновляю токен доступа, используя необработанный HTTP-запрос CURL, и он работает нормально.
gremo
Seorch ... вы еще не догадались? Здесь та же проблема.
Брайан Вандербуш
@gremo, не могли бы вы поделиться необработанным HTTP-запросом CURL, который вы использовали здесь? Было бы действительно полезно. Благодарность!
Silver Ringvee 07

Ответы:

76

Итак, я наконец понял, как это сделать. Основная идея состоит в том, что у вас есть токен, который вы получаете при первом запросе аутентификации. У этого первого токена есть токен обновления. Срок действия первого оригинального токена истекает через час. Через час вы должны использовать токен обновления из первого токена, чтобы получить новый пригодный для использования токен. Вы используете $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);
Ури Вег
источник
52
Вместо проверки в течение 3600 секунд вы должны использовать $ client-> isAccessTokenExpired ()
Гаурав Гупта
2
Небольшое обновление. В последней версии, когда вы запрашиваете токен обновления, теперь возвращается новый токен доступа с новым токеном обновления. По сути, вы можете использовать обновленный токен json для замены предыдущего токена json, и вам больше не нужно сохранять первоначальный токен доступа. .
skidadon
1
Обратите внимание, что по- $client->isAccessTokenExpired()прежнему будет проверяться только время, удерживаемое локально, чтобы узнать, считает ли он, что срок действия токена истек. Возможно, срок действия токена все еще истек, и локальное приложение действительно узнает об этом только тогда, когда попытается его использовать. В этом случае клиент API вернет исключение и не будет автоматически обновлять токен.
Джейсон
44

Проблема в токене обновления:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

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

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

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Я предполагаю, что вы сделали, так это то, что вы напечатали строку json, которую Google отправил обратно, скопировал и вставил токен в свой код, потому что, если вы json_decodeэто сделаете, он правильно удалит '\'за вас!

Асим
источник
1
удивительное упоминание, сделало мой день сэкономленные часы!
Мирча Санду
Ты спас мне день!
Чыонг Данг
Хотел бы я проголосовать за это 100 раз. Я собирался проделать дыру в стене с помощью клавиатуры после того, как в течение нескольких часов смотрел на сообщение «плохой грант» после того, как попробовал абсолютно все, чтобы заставить токен работать. Чертов гугл, зачем использовать слэши, зачем?
Аскерман
18

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

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()
Файшал
источник
1
вы сделали мой день с этим :) большое спасибо, это будет намного проще, чем я думал, так как я тратил много времени ни на что: D
TB Ygg
16

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

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

$client->setAccessType('offline');

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

jk.
источник
Спасибо, jk. Я загрузил последнюю версию и отозвал доступ к приложению для своей учетной записи. Затем я предоставил доступ еще раз и сохранил accessToken и refreshToken. Дело в том, что мне всегда давали refreshToken, даже если setAccessType был опущен. В любом случае, когда я запускаю $ client-> refreshToken (refresh-token-key), я все равно получаю ошибку «invalid_grant». Я проверил auth-url, по умолчанию он "force". Если я изменю его на «авто» и запустил метод проверки подлинности, я не буду перенаправлен, поскольку я уже предоставил доступ. Но ответ - это токен доступа без обновления. Любые идеи?
seorch.me
@ seorch.me Звучит безумно, но возможно ли, что вам нужно настроить new $client( $client = new apiClient();) для использования токена обновления?
jk.
1
@ seorch.me необходимо установить, $client->setApprovalPrompt('force')а также $client->setAccessType('offline')получить новый токен обновления при авторизации. Не заставляя пользователя утверждать объем доступа, Google предполагает, что вы собираетесь продолжать использовать старый токен обновления.
Джейсон
14

Ответ, опубликованный @ 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 refresh token)
    $this->saveAccessToken($client->getAccessToken());
}
Daishi
источник
отлично, много работали. Единственное, что я бы сказал, это то, что вы должны объяснить, что вам нужно передать объект json, а не только токен в виде строки.
Оливер Байес-Шелтон
@ OliverBayes-Shelton Привет. Спасибо. Я думал, // setAccessToken() expects jsonхватит. Или это для другой части кода?
Daishi
Это отлично работает для меня, но знаете ли вы, обрабатывает ли этот код ситуации, когда срок действия токена истекает из-за превышения лимита в 50 обновлений токена? Подробную информацию об истечении срока действия токена можно найти здесь: developers.google.com/identity/protocols/OAuth2#expiration
Bjorn
Кажется, что последняя версия 2.0 теперь возвращает токен обновления в массиве токенов доступа. Это означает, что при сохранении токена доступа сохраняется и токен обновления, так как токен обновления включен. В ответ на истечение срока действия токена обновления, я предполагаю, что его придется проверять и обрабатывать явно - помните, что ограничение в 50 - это «на пользователя на клиента», то есть 50 на клиента, поэтому вы вряд ли попадете в него, особенно если вы используете включенные области для объединения токенов.
Brian C
8

Вот код, который я использую в своем проекте, и он отлично работает:

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;
}
Мистер Грин
источник
6

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

По-видимому, это было из-за того, что мои системные часы были отключены на 2,5 (!!) секунды, синхронизация с NTP исправила это.

См. Также: https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors.

нападающий
источник
Этот ответ мне очень помог, чувак. Вы, наверное, сэкономили мне много времени. Много! Благодарность! Я просто выполнил sudo apt-get install ntpна своей машине Debian, чтобы установить NTP. Он синхронизировал часы, и проблема была решена.
Szymon Sadło
4

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

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

Марк Смит
источник
«Автоматически обновлять» означает, что мне просто нужно запросить getAccessToken (), и я верну обновленный? Но сначала мне нужно установить токен обновления из БД, верно? В противном случае обновление будет работать без токена обновления, и я не думаю, что это сработает,
ninsky 01
4

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

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

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 
Мину Шарма
источник
Чтобы быть более конкретным, похоже, что токен обновления включен в вашу первую авторизацию. Если вы сохраните, а затем используете его, я считаю (по мнению других, не проверено), что токен обновления продолжает возвращаться. В документе также говорится, что они будут автоматически обновлять токен доступа, если у них есть токен обновления, что означает, что это просто вопрос безопасного управления токеном обновления. setApprovalPrompt ('force') заставляет выдавать токен обновления впоследствии; без него вы не получите другого.
Brian C
2

Я использовал пример смарт-кодов с текущей версией Google API, но эта не сработала. Я считаю его API слишком устаревшим.

Итак, я просто написал свою собственную версию, основанную на одном из примеров API ... Он выводит токен доступа, токен запроса, тип токена, токен идентификатора, время истечения срока действия и время создания в виде строк.

Если ваши учетные данные клиента и ключ разработчика верны, этот код должен работать из коробки.

<?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>
Джон Слегерс
источник
1
Пожалуйста, не могли бы вы объяснить мне , почему эту строку: $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];. Почему вы перенаправляете на ту же страницу? это необходимо?
Tropicalista
@Tropicalista: нет необходимости перезагружать страницу как таковую, но обычно так реализуются потоки аутентификации.
Джон Слегерс
но вы не используете токен обновления для получения нового токена доступа, если срок действия токена доступа истек.
apadana
2

Вам необходимо сохранить токен доступа в файл или базу данных в виде строки json во время первоначального запроса авторизации и установить для типа доступа значение offline. $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()Функция будет делать работу за вас и предоставить новый маркер доступа, сохранить его обратно в файл или базу данных.

Сэм Томпсон
источник
1

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

Здесь это работает очень хорошо, может быть, это кому-нибудь поможет:

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();
}
?>
user1768700
источник
1

Google внес некоторые изменения с момента первоначальной публикации этого вопроса.

Вот мой рабочий пример.

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


}

источник
1

Я использую google-api-php-client v2.2.2. Я получаю новый токен с fetchAccessTokenWithRefreshToken();вызовом функции if без параметров, он возвращает обновленный токен доступа, и обновленный токен не теряется.

if ($client->getAccessToken() && $client->isAccessTokenExpired()) {
    $new_token=$client->fetchAccessTokenWithRefreshToken();
    $token_data = $client->verifyIdToken();
}    
Игорь Бурлов
источник
0

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

    <?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'];
    ?>
Аймен Муэли
источник
0

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

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

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

Джон
источник