Wie aktualisiere ich Token mit dem Google API-Client?

91

Ich habe mit der Google Analytics-API (V3) herumgespielt und bin auf einige Fehler gestoßen. Erstens ist alles korrekt eingerichtet und funktioniert mit meinem Testkonto. Wenn ich jedoch Daten von einer anderen Profil-ID (gleiches Google Accont / GA-Konto) abrufen möchte, wird ein 403-Fehler angezeigt. Das Seltsame ist, dass Daten von einigen GA-Konten Daten zurückgeben, während andere diesen Fehler erzeugen.

Ich habe das Token widerrufen und noch einmal authentifiziert, und jetzt kann ich anscheinend Daten von allen meinen Konten abrufen. Problem gelöst? Nicht. Da der Zugriffsschlüssel abläuft, werde ich erneut auf dasselbe Problem stoßen.

Wenn ich die Dinge richtig verstanden habe, könnte man das resfreshToken verwenden, um eine neue Authentifizierung zu erhalten.

Das Problem ist, wenn ich laufe:

$client->refreshToken(refresh_token_key) 

Der folgende Fehler wird zurückgegeben:

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

Ich habe den Code hinter der refreshToken-Methode überprüft und die Anforderung bis zur Datei "apiOAuth2.php" zurückverfolgt. Alle Parameter werden korrekt gesendet. Der grant_type ist innerhalb der Methode fest in 'refresh_token' codiert, daher fällt es mir schwer zu verstehen, was falsch ist. Das Parameterarray sieht folgendermaßen aus:

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

Das Verfahren ist wie folgt.

$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

Ist das ein Fehler oder habe ich etwas völlig falsch verstanden?

seorch.me
quelle
Ich weiß nicht, ob es sich um einen Fehler oder etwas anderes handelt, aber ich aktualisiere derzeit das Zugriffstoken mithilfe einer unformatierten CURL-http-Anforderung und es funktioniert einwandfrei.
Gremo
Seorch ... hast du das schon herausgefunden? Gleiches Problem hier.
Brian Vanderbusch
@gremo könntest du die rohe CURL http Anfrage teilen, die du hier verwendet hast? Wäre wirklich hilfreich. Vielen Dank!
Silver Ringvee

Antworten:

76

Also habe ich endlich herausgefunden, wie das geht. Die Grundidee ist, dass Sie das Token haben, das Sie erhalten, wenn Sie zum ersten Mal nach Authentifizierung fragen. Dieses erste Token verfügt über ein Aktualisierungstoken. Der erste Original-Token läuft nach einer Stunde ab. Nach einer Stunde müssen Sie das Aktualisierungstoken vom ersten Token verwenden, um ein neues verwendbares Token zu erhalten. Sie verwenden $client->refreshToken($refreshToken), um ein neues Token abzurufen. Ich werde dies "temporäres Token" nennen. Sie müssen dieses temporäre Token ebenfalls speichern, da es nach einer Stunde ebenfalls abläuft und kein Aktualisierungstoken zugeordnet ist. Um ein neues temporäres Token zu erhalten, müssen Sie die zuvor verwendete Methode verwenden und das Refreshtoken des ersten Tokens verwenden. Ich habe unten Code angehängt, was hässlich ist, aber ich bin neu in diesem ...

//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
quelle
52
Anstatt nach 3600 Sekunden zu suchen, sollten Sie $ client-> isAccessTokenExpired ()
Gaurav Gupta
2
Kleines Update. Wenn Sie in der neuesten Version ein Aktualisierungstoken anfordern, wird das zurückgegebene neue Zugriffstoken jetzt mit einem neuen Aktualisierungstoken geliefert. Im Wesentlichen können Sie das aktualisierte JSON-Token verwenden, um das vorherige JSON-Token zu ersetzen, und müssen das Erstzugriffstoken nicht länger beibehalten. .
Skidadon
1
Beachten Sie, dass $client->isAccessTokenExpired()weiterhin nur die lokal gehaltenen Zeiten überprüft werden, um festzustellen, ob das Token abgelaufen ist. Das Token ist möglicherweise noch abgelaufen und die lokale Anwendung weiß erst wirklich, wann sie versucht, es zu verwenden. In diesem Fall gibt der API-Client eine Ausnahme zurück und aktualisiert das Token nicht automatisch.
Jason
44

Das Problem liegt im Aktualisierungstoken:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Wenn ein String mit einem '/'get wird json encoded, wird er mit einem '\'maskiert, daher müssen Sie ihn entfernen.

Das Aktualisierungstoken in Ihrem Fall sollte sein:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

Ich gehe davon aus, dass Sie die JSON-Zeichenfolge gedruckt haben, die Google zurückgesendet und das Token kopiert und in Ihren Code eingefügt hat, denn wenn Sie json_decodees tun, wird es das '\'für Sie korrekt entfernen !

Asim
quelle
1
erstaunliche Erwähnung, machte meinen Tag! Stunden gespart!
Mircea Sandu
Du hast meinen Tag gerettet !
Truong Dang
Ich wünschte, ich könnte dies 100 Mal positiv bewerten. Ich wollte gerade mit meiner Tastatur ein Loch in eine Wand bohren, nachdem ich mehrere Stunden lang auf die Meldung "Bad Grant" gestarrt hatte, nachdem ich absolut alles versucht hatte, damit der Token funktioniert. Fricking Google Man, warum Schrägstriche verwenden, nur warum?
Askerman
18

Hier ist das Snippet zum Festlegen des Tokens. Stellen Sie zuvor sicher, dass der Zugriffstyp auf Offline gesetzt ist

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

Token aktualisieren

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

Dadurch wird Ihr Token aktualisiert. Sie müssen es in der Sitzung aktualisieren, damit Sie dies tun können

 $_SESSION['access_token']= $client->getAccessToken()
Faishal
quelle
1
Du hast meinen Tag damit gemacht :) Vielen Dank, viel einfacher als ich dachte, da ich viel Zeit damit verbracht habe, nirgendwo hin zu kommen: D
TB Ygg
16

Der Zugriffstyp sollte auf eingestellt sein offline. stateist eine Variable, die Sie für Ihren eigenen Gebrauch festlegen, nicht für die Verwendung durch die API.

Stellen Sie sicher, dass Sie über die neueste Version der Clientbibliothek verfügen, und fügen Sie Folgendes hinzu:

$client->setAccessType('offline');

Eine Erläuterung der Parameter finden Sie unter Erstellen der URL .

jk.
quelle
Danke jk. Ich habe die neueste Version heruntergeladen und den Zugriff auf die App für mein Konto widerrufen. Dann habe ich noch einmal Zugriff gewährt und das accessToken und das refreshToken gespeichert. Die Sache ist, ich habe immer ein refreshToken erhalten, auch wenn der setAccessType weggelassen wurde. Wenn ich $ client-> refreshToken (refresh-token-key) ausführe, wird trotzdem der Fehler "invalid_grant" angezeigt. Ich habe die Auth-URL überprüft und sie ist standardmäßig "erzwingen". Wenn ich es in "auto" ändere und die Authentifizierungsmethode ausführe, werde ich nicht umgeleitet, da ich bereits Zugriff gewährt habe. Die Antwort ist jedoch ein accessToken ohne Aktualisierung. Irgendwelche Ideen?
seorch.me
@ seorch.me Klingt verrückt, aber ist es möglich, dass Sie ein neues $client( $client = new apiClient();) einrichten müssen , um das Aktualisierungstoken zu verwenden?
jk.
1
@ seorch.me müssen Sie festlegen $client->setApprovalPrompt('force')sowie $client->setAccessType('offline')ein neues Aktualisierungstoken während der Autorisierung erhalten. Ohne den Nutzer zu zwingen, den Zugriffsbereich zu genehmigen, geht Google davon aus, dass Sie das alte Aktualisierungstoken weiterhin verwenden werden.
Jason
14

Die Antwort von @ uri-weg hat bei mir funktioniert, aber da ich seine Erklärungen nicht sehr klar fand, möchte ich sie ein wenig umformulieren.

Wenn Sie während der ersten Zugriffsberechtigungssequenz im Rückruf den Punkt erreichen, an dem Sie einen Authentifizierungscode erhalten, müssen Sie auch das Zugriffstoken und das Aktualisierungstoken speichern .

Der Grund dafür ist, dass Google API Ihnen nur dann ein Zugriffstoken mit einem Aktualisierungstoken sendet, wenn Sie zur Eingabe der Zugriffsberechtigung aufgefordert werden. Die nächsten Zugriffstoken werden ohne Aktualisierungstoken gesendet (es sei denn, Sie verwenden die approval_prompt=forceOption).

Das Aktualisierungstoken, das Sie zum ersten Mal erhalten haben, bleibt gültig, bis der Benutzer die Zugriffsberechtigung widerruft.

In vereinfachter PHP wäre ein Beispiel für die Rückrufsequenz:

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

Und später, in vereinfachtem PHP, wäre die Verbindungssequenz:

// 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
quelle
perfekt, hat viel funktioniert. Ich würde nur sagen, dass Sie erklären sollten, dass Sie das JSON-Objekt und nicht nur das Token als Zeichenfolge übergeben müssen.
Oliver Bayes-Shelton
@ OliverBayes-Shelton Hallo. Vielen Dank. Ich fand // setAccessToken() expects jsondas ausreichend. Oder ist es für einen anderen Teil des Codes?
Daishi
Das funktioniert gut für mich, aber wissen Sie, ob dieser Code Situationen behandelt, in denen ein Token abläuft, weil das Limit von 50 Token-Aktualisierungen überschritten wird? Details zu 'Token Expiration' finden Sie hier: developer.google.com/identity/protocols/OAuth2#expiration
Björn
Es scheint, dass die neueste Version 2.0 jetzt das Aktualisierungstoken im Zugriffstoken-Array zurückgibt. Dies bedeutet, dass beim Speichern des Zugriffstokens auch das Aktualisierungstoken gespeichert wird, da das Aktualisierungstoken enthalten ist. Als Reaktion darauf, dass das Aktualisierungstoken abläuft, muss dies vermutlich explizit getestet und behandelt werden. Denken Sie daran, dass das 50-Limit "pro Benutzer pro Client" ist, dh 50 pro Client, sodass Sie es wahrscheinlich nicht treffen werden, insbesondere wenn Sie verwenden mitgelieferte Bereiche, um Token zu kombinieren.
Brian C
8

Hier ist der Code, den ich in meinem Projekt verwende und der gut funktioniert:

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;
}
Herr Green
quelle
6

Hatte das gleiche Problem; Mein Skript, das gestern aus irgendeinem Grund funktioniert hat, hat heute nicht funktioniert. Keine Änderungen.

Anscheinend lag dies daran, dass meine Systemuhr um 2,5 (!!) Sekunden ausgeschaltet war und durch die Synchronisierung mit NTP behoben wurde.

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

strikernl
quelle
Diese Antwort hat mir sehr geholfen, Mann. Sie haben mir wahrscheinlich viel Zeit gespart. Viel! Vielen Dank! Ich habe gerade sudo apt-get install ntpauf meinem Debian-Computer ausgeführt, um NTP zu installieren. Es synchronisierte die Uhr und das Problem wurde gelöst.
Szymon Sadło
4

Zu Ihrer Information: Die Google Analytics-API 3.0 aktualisiert das Zugriffstoken automatisch, wenn Sie ein Aktualisierungstoken haben, wenn es abläuft, sodass Ihr Skript es nie benötigt refreshToken .

(Siehe die SignFunktion in auth/apiOAuth2.php)

Mark Smith
quelle
"Automatisch aktualisieren" bedeutet, dass ich nur nach getAccessToken () fragen muss und ein aktualisiertes zurück bekomme? Aber ich muss zuerst das Aktualisierungstoken aus der Datenbank setzen, oder? Andernfalls würde die Aktualisierung ohne ein Aktualisierungstoken funktionieren, und ich glaube nicht, dass dies funktionieren würde
ninsky
4

Manchmal wird ein Aktualisierungstoken nicht mithilfe von generiert $client->setAccessType ("offline"); .

Versuche dies:

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 
Meenu Sharma
quelle
Genauer gesagt sieht es so aus, als ob das Aktualisierungstoken in Ihrer ersten Autorisierung enthalten ist. Wenn Sie es speichern und dann verwenden, glaube ich (laut anderen nicht verifiziert), dass das Aktualisierungstoken weiterhin zurückgegeben wird. Das Dokument sagt jetzt auch, dass sie das Zugriffstoken automatisch aktualisieren, wenn sie ein Aktualisierungstoken haben, was bedeutet, dass es einfach darum geht, das Aktualisierungstoken sicher zu verwalten. setApprovalPrompt ('force') erzwingt die anschließende Ausgabe eines Aktualisierungstokens. ohne sie bekommst du keinen anderen.
Brian C
2

Ich habe das Beispiel von Smartcodes mit der aktuellen Version der Google-API verwendet, aber diese hat nicht funktioniert. Ich denke, seine API ist zu veraltet.

Also habe ich gerade meine eigene Version geschrieben, basierend auf einem der API-Beispiele ... Sie gibt Zugriffstoken, Anforderungstoken, Tokentyp, ID-Token, Ablaufzeit und Erstellungszeit als Zeichenfolgen aus

Wenn Ihre Client-Anmeldeinformationen und Ihr Entwicklerschlüssel korrekt sind, sollte dieser Code sofort funktionieren.

<?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
quelle
1
Könnten Sie mir bitte erklären, warum diese Zeile : $redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];. Warum leiten Sie zur gleichen Seite weiter? ist das notwendig?
Tropicalista
@Tropicalista: Es ist nicht erforderlich, die Seite per se neu zu laden, aber auf diese Weise werden Authentifizierungsabläufe normalerweise implementiert.
John Slegers
Sie verwenden das Aktualisierungstoken jedoch nicht, um ein neues Zugriffstoken abzurufen, wenn das Zugriffstoken abgelaufen ist.
Apadana
1

Ich habe das gleiche Problem mit Google / Google-API-PHP-Client v2.0.0-RC7 und nach 1-stündiger Suche habe ich dieses Problem mit json_encode wie folgt gelöst :

    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
quelle
1

Das hier funktioniert sehr gut, vielleicht könnte es jedem helfen:

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
quelle
1

Google hat einige Änderungen vorgenommen, seit diese Frage ursprünglich veröffentlicht wurde.

Hier ist mein aktuelles Arbeitsbeispiel.

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


}
Dave Spelts
quelle
1

Ich verwende google-api-php-client v2.2.2 Ich erhalte ein neues Token mit einem fetchAccessTokenWithRefreshToken();Funktionsaufruf ohne Parameter, der ein aktualisiertes Zugriffstoken zurückgibt und das aktualisierte Token nicht verloren geht.

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

Sie müssen das Zugriffstoken während der Erstautorisierungsanforderung als JSON-Zeichenfolge in einer Datei oder Datenbank speichern und den Zugriffstyp auf Offline setzen $client->setAccessType("offline")

Nehmen Sie dann bei nachfolgenden API-Anforderungen das Zugriffstoken aus Ihrer Datei oder Datenbank und übergeben Sie es an den Client:

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

Jetzt müssen Sie überprüfen, ob das Token abgelaufen ist:

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

Die fetchAccessTokenWithRefreshToken()Funktion erledigt die Arbeit für Sie und stellt ein neues Zugriffstoken bereit. Speichern Sie es zurück in Ihrer Datei oder Datenbank.

Sam Thompson
quelle
0

Gemäß Authentifizierung bei Google: OAuth2 gibt immer wieder "invalid_grant" zurück.

"Sie sollten das Zugriffstoken, das Sie nach der ersten erfolgreichen Authentifizierung erhalten, wiederverwenden. Wenn Ihr vorheriges Token noch nicht abgelaufen ist, wird der Fehler invalid_grant angezeigt. Speichern Sie es irgendwo, damit Sie es wiederverwenden können."

ich hoffe es hilft

Jon
quelle
-1

Verwenden Sie das folgende Codefragment, um Ihr Aktualisierungstoken abzurufen

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