Jak odświeżyć token za pomocą klienta Google API?

92

Bawiłem się interfejsem API Google Analytics (V3) i napotkałem pewne błędy. Po pierwsze, wszystko jest poprawnie skonfigurowane i działa z moim kontem testowym. Ale kiedy chcę pobrać dane z innego identyfikatora profilu (to samo konto Google Accont / GA), pojawia się błąd 403. Dziwne jest to, że dane z niektórych kont GA zwracają dane, podczas gdy inne generują ten błąd.

Wycofałem token i uwierzytelniłem się jeszcze raz, a teraz wygląda na to, że mogę pobrać dane ze wszystkich moich kont. Problem rozwiązany? Nie. Ponieważ klucz dostępu wygaśnie, ponownie napotkam ten sam problem.

Jeśli dobrze zrozumiałem, można użyć resfreshToken, aby uzyskać nowy plik authenticationTooken.

Problem w tym, że kiedy biegam:

$client->refreshToken(refresh_token_key) 

zwracany jest następujący błąd:

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

Sprawdziłem kod za metodą refreshToken i prześledziłem żądanie z powrotem do pliku „apiOAuth2.php”. Wszystkie parametry są wysyłane poprawnie. Grant_type jest zakodowany na stałe jako „refresh_token” w metodzie, więc trudno mi zrozumieć, co jest nie tak. Tablica parametrów wygląda następująco:

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

Procedura jest następująca.

$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

Czy to błąd, czy kompletnie coś źle zrozumiałem?

seorch.me
źródło
Nie wiem, czy to błąd, czy coś, ale obecnie odświeżam token dostępu za pomocą surowego żądania http CURL i działa dobrze.
gremo
Seorch ... już to rozgryzłeś? Ten sam problem tutaj.
Brian Vanderbusch,
@gremo czy możesz udostępnić surowe żądanie HTTP CURL, którego użyłeś tutaj? Byłoby naprawdę pomocne. Dzięki!
Silver Ringvee

Odpowiedzi:

76

Więc w końcu wymyśliłem, jak to zrobić. Podstawową ideą jest to, że masz token, który otrzymujesz, gdy pierwszy raz poprosisz o uwierzytelnienie. Ten pierwszy token zawiera token odświeżania. Pierwszy oryginalny token traci ważność po godzinie. Po godzinie musisz użyć tokena odświeżania z pierwszego tokena, aby uzyskać nowy użyteczny token. Używasz $client->refreshToken($refreshToken)do pobierania nowego tokena. Nazwę to „tymczasowym tokenem”. Musisz również przechowywać ten tymczasowy token, ponieważ po godzinie również wygasa i zauważ, że nie ma skojarzonego z nim tokena odświeżania. Aby uzyskać nowy tymczasowy token, musisz użyć metody, z której korzystałeś wcześniej i użyć refreshtoken pierwszego tokena. Załączam kod poniżej, który jest brzydki, ale jestem nowy w tym ...

//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);
Uri Weg
źródło
52
Zamiast sprawdzać przez 3600 sekund, powinieneś użyć $ client-> isAccessTokenExpired ()
Gaurav Gupta
2
Mała aktualizacja. W najnowszej wersji, gdy zażądasz tokenu odświeżania, nowy token dostępu, który jest teraz zwracany, zawiera nowy token odświeżania. Zasadniczo można więc użyć zaktualizowanego tokenu json, aby zastąpić poprzedni token json i nie trzeba już dłużej zachowywać początkowego tokenu dostępu. .
skidadon
1
Pamiętaj, że $client->isAccessTokenExpired()nadal będzie sprawdzać tylko czasy przechowywane lokalnie, aby sprawdzić, czy uważa, że ​​token wygasł. Token mógł nadal wygasnąć, a lokalna aplikacja będzie naprawdę wiedzieć tylko wtedy, gdy spróbuje go użyć. W takim przypadku klient API zwróci wyjątek i nie odświeży automatycznie tokena.
Jason,
@Jason Myślę, że teraz nie prawda. W metodzie „isAccessTokenExpired” widzę poniższą instrukcję powrotu: return ($ created + ($ this-> token ['expires_in'] - 30)) <time ();
sudip
44

Problem dotyczy tokena odświeżania:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Kiedy ciąg z a '/'dostaje json encoded, jest uciekany z a '\', dlatego musisz go usunąć.

Token odświeżania w Twoim przypadku powinien wyglądać następująco:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Zakładam, że zrobiłeś to, że wydrukowałeś ciąg json, który Google odesłał, a następnie skopiował i wkleił token do twojego kodu, ponieważ jeśli json_decodeto zrobisz , to poprawnie usunie '\'za ciebie!

Asim
źródło
1
niesamowita wzmianka, sprawiła, że ​​mój dzień! zaoszczędzone godziny!
Mircea Sandu
Uratowałeś mi dzień!
Truong Dang
Chciałbym móc zagłosować za tym 100 razy. Już miałem zrobić dziurę w ścianie klawiaturą po tym, jak przez kilka godzin wpatrywałem się w komunikat „zły grant” po wypróbowaniu absolutnie wszystkiego, aby token działał. Pieprzony Google, po co używać ukośników, tylko dlaczego?
Askerman
18

oto fragment do ustawienia tokena, przedtem upewnij się, że typ dostępu powinien być ustawiony na offline

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

Aby odświeżyć token

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

to odświeży twój token, musisz go zaktualizować w sesji, aby to zrobić

 $_SESSION['access_token']= $client->getAccessToken()
Faishal
źródło
1
sprawiłeś, że mi się to udało :) dziękuję bardzo, dużo prostsze niż myślałem, ponieważ spędzam dużo czasu, docierając donikąd: D
TB Ygg
16

Należy ustawić typ dostępu na offline. statejest zmienną ustawianą na własny użytek, a nie na użytek interfejsu API.

Upewnij się, że masz najnowszą wersję biblioteki klienta i dodaj:

$client->setAccessType('offline');

Aby uzyskać wyjaśnienie parametrów, zobacz Tworzenie adresu URL .

jk.
źródło
Dzięki jk. Pobrałem najnowszą wersję i odebrałem dostęp do aplikacji dla mojego konta. Następnie jeszcze raz przyznałem dostęp i zapisałem accessToken i refreshToken. Rzecz w tym, że zawsze otrzymywałem refreshToken, nawet jeśli pominięto setAccessType. W każdym razie, kiedy uruchamiam $ client-> refreshToken (refresh-token-key), nadal otrzymuję błąd „invalid_grant”. Sprawdziłem auth-url i domyślnie jest to „wymuszone”. Jeśli zmienię to na „auto” i uruchomię metodę uwierzytelniania, nie nastąpi przekierowanie, ponieważ już udzieliłem dostępu. Ale odpowiedź jest accessTokenem bez odświeżania. Jakieś pomysły?
seorch.me
@ seorch.me Brzmi szaleńczo, ale czy jest możliwe, że musisz skonfigurować new $client( $client = new apiClient();), aby używać tokena odświeżania?
jk.
1
@ seorch.me musisz ustawić, $client->setApprovalPrompt('force')a także $client->setAccessType('offline')uzyskać nowy token odświeżania podczas autoryzacji. Bez zmuszania użytkownika do zatwierdzenia zakresu dostępu Google zakłada, że ​​będziesz nadal używać starego tokena odświeżania.
Jason,
14

Odpowiedź zamieszczona przez @ uri-weg zadziałała dla mnie, ale ponieważ jego wyjaśnienia nie były dla mnie zbyt jasne, pozwolę sobie trochę przeformułować.

Podczas pierwszej sekwencji uprawnień dostępu, w wywołaniu zwrotnym, gdy dojdziesz do punktu, w którym otrzymasz kod uwierzytelniający, musisz również zapisać token dostępu oraz token odświeżania .

Powodem jest to, że Google API wysyła token dostępu z tokenem odświeżania tylko wtedy, gdy prosi o pozwolenie na dostęp. Kolejne tokeny dostępu zostaną wysłane bez odświeżania tokena (chyba że skorzystasz z approval_prompt=forceopcji).

Token odświeżania, który otrzymałeś za pierwszym razem, zachowuje ważność, dopóki użytkownik nie cofnie uprawnień dostępu.

W uproszczonym php, przykładem sekwencji wywołania zwrotnego byłoby:

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

A później, w uproszczonym php, sekwencja połączeń wyglądałaby następująco:

// 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
źródło
idealnie, dużo pracował. Powiedziałbym tylko, że powinieneś wyjaśnić, że musisz przekazać obiekt json, a nie tylko token jako ciąg.
Oliver Bayes-Shelton
@ OliverBayes-Shelton Hi. Dzięki. Myślałem, że // setAccessToken() expects jsonto wystarczy. A może dotyczy innej części kodu?
Daishi
U mnie to działa świetnie, ale czy wiesz, czy ten kod obsługuje sytuacje, w których token wygasa z powodu przekroczenia limitu 50 odświeżeń tokena? Szczegółowe informacje na temat „wygaśnięcia tokena” można znaleźć tutaj: developers.google.com/identity/protocols/OAuth2#expiration
Bjorn
Wygląda na to, że najnowsza wersja 2.0 zwraca teraz token odświeżania w tablicy tokenu dostępu. Oznacza to, że zapisanie tokena dostępu powoduje również zapisanie tokena odświeżania, ponieważ zawiera token odświeżania. Zgaduję, że w odpowiedzi na wygaśnięcie tokena odświeżania musiałoby to zostać przetestowane i potraktowane jawnie - pamiętaj, że limit 50 to „na użytkownika na klienta”, tj. Jest to 50 na klienta, więc jest mało prawdopodobne, że go osiągniesz, zwłaszcza jeśli używasz dołączonych zakresów do łączenia tokenów.
Brian C
8

Oto kod, którego używam w moim projekcie i działa dobrze:

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;
}
Pan Zielony
źródło
6

Miał ten sam problem; mój skrypt, który działał wczoraj, z jakiegoś dziwnego powodu nie działał dzisiaj. Bez zmian.

Najwyraźniej było tak, ponieważ mój zegar systemowy był wyłączony o 2,5 (!!) sekundy, synchronizacja z NTP naprawiła to.

Zobacz też: https://code.google.com/p/google-api-php-client/wiki/OAuth2#Solving_invalid_grant_errors

strikernl
źródło
Ta odpowiedź bardzo mi pomogła, stary. Prawdopodobnie zaoszczędziłeś mi dużo czasu. Dużo! Dzięki! Właśnie wykonałem sudo apt-get install ntpna mojej maszynie Debiana, aby zainstalować NTP. Zsynchronizował zegar i problem został rozwiązany.
Szymon Sadło
4

Do Twojej wiadomości: 3.0 Google Analytics API automatycznie odświeży token dostępu, jeśli masz token odświeżania po jego wygaśnięciu, więc twój skrypt nigdy nie potrzebuje refreshToken.

(Zobacz Signfunkcję w auth/apiOAuth2.php)

Mark Smith
źródło
„Odświeżaj automatycznie” oznacza, że ​​po prostu muszę poprosić o getAccessToken () i otrzymam z powrotem odświeżony? Ale najpierw muszę ustawić token odświeżania z bazy danych, prawda? W przeciwnym razie odświeżanie działałoby bez tokena odświeżania i nie sądzę, aby to zadziałało
ninsky
4

Czasami Refresh Token nie został wygenerowany przy użyciu $client->setAccessType ("offline");.

Spróbuj tego:

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 
Meenu Sharma
źródło
Mówiąc dokładniej, wygląda na to, że token Refresh jest zawarty w Twojej pierwszej autoryzacji. Jeśli go zapiszesz, a następnie użyjesz, uważam (według innych, niezweryfikowany), że token odświeżania jest nadal zwracany. Dokument doco mówi teraz również, że będą automatycznie odświeżać token dostępu, jeśli mają token odświeżania, co oznacza, że ​​jest to po prostu kwestia bezpiecznego zarządzania tokenem odświeżania. setApprovalPrompt ('force') wymusza późniejsze wydanie tokena odświeżania; bez niego nie dostaniesz kolejnego.
Brian C
2

Skorzystałem z przykładu przez smartcodes z aktualną wersją API Google, ale ten nie zadziałał. Myślę, że jego API jest zbyt przestarzałe.

Właśnie napisałem własną wersję, opartą na jednym z przykładów API ... Wyprowadza token dostępu, token żądania, typ tokenu, token identyfikatora, czas wygaśnięcia i czas utworzenia jako ciągi

Jeśli poświadczenia klienta i klucz programisty są poprawne, ten kod powinien działać po wyjęciu z pudełka.

<?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>
John Slegers
źródło
1
Proszę, możesz mi wyjaśnić, dlaczego ten wiersz: $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];. Dlaczego przekierowujesz na tę samą stronę? czy to konieczne?
Tropicalista,
@Tropicalista: Nie jest konieczne ponowne ładowanie strony jako takiej, ale w ten sposób zwykle realizowane są przepływy uwierzytelniania.
John Slegers,
ale nie używasz tokena odświeżania do uzyskania nowego tokenu dostępu, jeśli token dostępu wygasł.
apadana,
2

Musisz zapisać token dostępu do pliku lub bazy danych jako ciąg json podczas początkowego żądania autoryzacji i ustawić typ dostępu na offline $client->setAccessType("offline")

Następnie, podczas kolejnych żądań API, pobierz token dostępu ze swojego pliku lub bazy danych i przekaż go klientowi:

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

Teraz musisz sprawdzić, czy token wygasł:

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()Funkcja wykona pracę za Ciebie i dostarczenie nowego tokenu dostępu, zapisać go z powrotem do pliku lub bazy danych.

Sam Thompson
źródło
1

Mam ten sam problem z google / google-api-php-client v2.0.0-RC7 i po 1 godzinach wyszukiwania rozwiązałem ten problem używając json_encode w następujący sposób:

    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()));
    }
Grandong
źródło
1

To tutaj działa bardzo dobrze, może mogłoby komuś pomóc:

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
źródło
1

Firma Google wprowadziła pewne zmiany od czasu opublikowania tego pytania.

Oto mój obecnie działający przykład.

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


}

źródło
1

Używam google-api-php-client v2.2.2. Otrzymuję nowy token z fetchAccessTokenWithRefreshToken();wywołaniem funkcji if bez parametrów, zwraca zaktualizowany token dostępu, a odświeżony token nie jest utracony.

if ($client->getAccessToken() && $client->isAccessTokenExpired()) {
    $new_token=$client->fetchAccessTokenWithRefreshToken();
    $token_data = $client->verifyIdToken();
}    
Igor Burlov
źródło
0

użyj poniższego fragmentu kodu, aby uzyskać token odświeżania

    <?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'];
    ?>
Aymen Mouelhi
źródło