Comment rafraîchir token avec Google API client?

j'ai joué avec L'API Google Analytics (V3) et j'ai rencontré des erreurs som. Tout d'abord, tout est mis en place correctement et fonctionne avec mon compte de test. Mais lorsque je veux récupérer des données à partir d'un autre identifiant de profil (même compte Google Accont/GA), j'obtiens une erreur 403. La chose étrange est que les données de certains comptes GA retourneront des données tandis que d'autres génèrent cette erreur.

j'ai révoqué le jeton et authentifié une fois de plus, et maintenant il semble que je peux récupérez les données de tous mes comptes. Le problème est résolu? Pas. Comme la clé d'accès expirera, je rencontrerai le même problème à nouveau.

si j'ai bien compris les choses, on pourrait utiliser le resfreshToken pour obtenir une nouvelle authentificationtooken.

le problème est, quand je cours:

$client->refreshToken(refresh_token_key) 

l'erreur suivante est renvoyée:

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

j'ai vérifié le code derrière la méthode refreshToken demande de retour au " apiOAuth2.php fichier". Tous les paramètres sont envoyés correctement. Le type grant_type est difficilement codé en 'refresh_token' dans la méthode, donc il est difficile pour moi de comprendre ce qui ne va pas. Le tableau des paramètres ressemble à ceci:

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

la procédure est la suivante.

$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

Est-ce un bug ou ai-je complètement mal compris quelque chose?

77
demandé sur Roman Starkov 2012-02-11 19:07:27

15 réponses

donc j'ai finalement trouvé comment faire ça. L'idée de base est que vous avez le jeton que vous obtenez la première fois que vous demandez pour l'authentification. Ce premier jeton a un jeton de rafraîchissement. Le premier jeton original expire après une heure. Après une heure, vous devez utiliser le jeton d'actualisation de la première gage pour obtenir un nouveau utilisable jeton. Vous utilisez $client->refreshToken($refreshToken) pour récupérer un nouveau jeton. Je vais appeler cette "temp jeton."Vous devez stocker ce jeton temporaire aussi bien parce qu'après une heure il expire aussi bien et remarque il n'a pas un jeton d'actualisation associé. Pour obtenir un nouveau token temporaire, vous devez utiliser la méthode que vous avez utilisée avant et utiliser le refreshtoken du premier token. J'ai joint le code ci-dessous, ce qui est laid, mais im nouveau à cela...

//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);
67
répondu Uri Weg 2013-03-13 18:31:32

Le problème est dans le jeton d'actualisation:

[refresh_token] => 1\/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

quand une chaîne avec un '/' obtient json encoded , elle est échappée avec un '\' , donc vous devez l'enlever.

le jeton de rafraîchissement dans votre cas devrait être:

1/lov250YQTMCC9LRQbE6yMv-FiX_Offo79UXimV8kvwY

ce que je suppose que vous avez fait est que vous avez imprimé la chaîne json que google a envoyé et copié et collé le jeton dans votre code parce que si vous json_decode il alors il supprimera correctement le '\' pour vous!

36
répondu Asim 2015-07-27 04:49:14

Le type d'accès doit être réglé sur offline . state est une variable que vous définissez pour votre propre utilisation, et non pour l'utilisation de l'API.

assurez - vous que vous avez la dernière version de la bibliothèque client et ajouter:

$client->setAccessType('offline');

Voir Formant l'URL pour une explication des paramètres.

17
répondu jk. 2012-02-11 22:00:57

voici le fragment pour définir le token, avant cela assurez-vous que le type d'accès doit être défini à offline

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

pour rafraîchir le jeton

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

cela va rafraîchir votre token, vous devez le mettre à jour en session pour que vous puissiez le faire

 $_SESSION['access_token']= $client->getAccessToken()
17
répondu Strik3r 2013-02-26 05:30:52

la réponse Postée par @uri-weg a fonctionné pour moi mais comme je n'ai pas trouvé ses explications très claires, permettez-moi de la reformuler un peu.

pendant la première séquence de permission d'accès, dans le rappel, lorsque vous arrivez au point où vous recevez un code d'authentification, vous devez enregistrer le token d'accès et le token de rafraîchissement aussi.

la raison est que l'api google vous envoie un token d'accès avec un actualiser jeton uniquement lors d'une demande d'autorisation d'accès. Les tokens d'accès suivants seront envoyés sans aucun token de rafraîchissement (à moins que vous n'utilisiez l'option approval_prompt=force ).

le jeton de rafraîchissement que vous avez reçu la première fois reste valide jusqu'à ce que l'utilisateur révoque la permission d'accès.

en php simpliste, un exemple de la séquence de rappel serait:

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

et plus tard, en php simpliste, la connexion la séquence serait:

// 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());
}
13
répondu Daishi 2018-06-12 22:46:00

Voici le code que j'utilise dans mon projet et il fonctionne très bien:

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;
}
7
répondu Mr_Green 2016-12-16 16:43:26

avait le même problème; mon script qui a fonctionné hier, pour une raison étrange ne l'a pas fait aujourd'hui. Pas de changements.

apparemment, c'était parce que mon horloge système était éteinte de 2,5 (!!) secondes, la synchronisation avec NTP fixe.

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

6
répondu strikernl 2012-08-23 07:48:04

POUR INFO: L'API Google Analytics 3.0 rafraîchira automatiquement le token d'accès si vous avez un token de rafraîchissement à la date d'expiration de sorte que votre script n'a jamais besoin de refreshToken .

(voir la fonction Sign dans auth/apiOAuth2.php )

3
répondu Mark Smith 2012-09-16 09:58:39

j'ai utilisé l'exemple de smartcodes avec la version actuelle de L'API Google, mais celle-ci n'a pas fonctionné. Je pense que son API est trop périmée.

donc, je viens d'écrire ma propre version, basée sur l'un des exemples API... Il affiche le jeton d'accès, le jeton de requête, le type de jeton, le jeton D'ID, le temps d'expiration et le temps de création comme chaînes

si vos justificatifs d'identité de client et votre clé de développeur sont corrects, ce code devrait fonctionner hors de la boîte.

<?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>
2
répondu John Slegers 2016-01-15 15:47:03

rafraîchit parfois le jeton que je n'ai pas généré en utilisant $client->setAccessType ("offline"); .

essayez ceci:

$client->setAccessType ("offline");
$client->setApprovalPrompt ("force"); 
2
répondu Meenu Sharma 2017-02-14 13:38:26

j'ai le même problème avec google/google-api-php-client v2.0.151930920" et après avoir cherché pendant 1 heure, j'ai résolu ce problème en utilisant json_encode comme ceci:

    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
répondu Grandong 2016-05-08 10:10:31

ceci ici fonctionne très bien, peut-être qu'il pourrait aider n'importe qui:

de l'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();

?>

du 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();
}
?>
1
répondu user1768700 2017-08-05 15:56:06

selon authentification sur google: OAuth2 continue à retourner "invalid_grant"

" vous devez réutiliser le jeton d'accès que vous obtenez après la première authentification réussie. Vous obtiendrez une erreur invalid_grant si votre jeton précédent n'est pas encore expiré. Cache quelque part afin de la réutiliser."

j'espère que ça aide

0
répondu Jon 2017-05-23 12:34:59

Google a fait quelques changements depuis que cette question a été initialement posté.

Voici mon exemple actuel.

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


}
0
répondu Dave Spelts 2018-07-18 14:14:24

utilisez l'extrait de code suivant pour obtenir votre jeton de rafraîchissement

    <?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'];
    ?>
-1
répondu Aymen Mouelhi 2012-07-03 17:09:49