简体   繁体   English

具有公共访问权限的Web应用程序的Google OAuth 2.0刷新令牌

[英]Google OAuth 2.0 refresh token for web application with public access

I'm getting the following error: 我收到以下错误:

The OAuth 2.0 access token has expired, and a refresh token is not available. OAuth 2.0访问令牌已过期,并且刷新令牌不可用。 Refresh tokens are not returned for responses that were auto-approved 对于自动批准的响应,不会返回刷新令牌

I have a web application which only my server will be accessing, the initial auth works fine, but after an hour, the aforementioned error message pops up. 我有一个只有我的服务器才能访问的Web应用程序,初始身份验证工作正常,但一小时后,弹出上述错误消息。 My script looks like this: 我的脚本看起来像这样:

require_once 'Google/Client.php';     
require_once 'Google/Service/Analytics.php';       
session_start();

$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$client->setDeveloperKey("{MY_API_KEY}");
$client->setClientId('{MY_CLIENT_ID}.apps.googleusercontent.com');
$client->setClientSecret('{MY_KEY}');
$client->setRedirectUri('{MY_REDIRECT_URI}');
$client->setScopes(array('https://www.googleapis.com/auth/gmail.readonly'));

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

if (!$client->getAccessToken() && !isset($_SESSION['token'])) {
    $authUrl = $client->createAuthUrl();
    print "<a class='login' href='$authUrl'>Connect Me!</a>";
}

How can I set up a refresh token for this? 如何为此设置刷新令牌?

Edit 1: I've tried doing this with a Service account as well. 编辑1:我也尝试过使用服务帐户。 I followed the documentation available on GitHub: 我按照GitHub上提供的文档:

https://github.com/google/google-api-php-client/blob/master/examples/service-account.php https://github.com/google/google-api-php-client/blob/master/examples/service-account.php

My script looks like this: 我的脚本看起来像这样:

session_start();
include_once "templates/base.php";
require_once 'Google/Client.php';
require_once 'Google/Service/Gmail.php';
$client_id = '{MY_CLIENT_ID}.apps.googleusercontent.com'; 
$service_account_name = '{MY_EMAIL_ADDRESS}@developer.gserviceaccount.com ';
$key_file_location = 'Google/{MY_KEY_FILE}.p12';
echo pageHeader("Service Account Access");
    if ($client_id == ''
|| !strlen($service_account_name)
|| !strlen($key_file_location)) {
  echo missingServiceAccountDetailsWarning();
}
$client = new Google_Client();
$client->setApplicationName("Client_Library_Examples");
$service = new Google_Service_Gmail($client);
if (isset($_SESSION['service_token'])) {
  $client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
    $service_account_name,
    array('https://www.googleapis.com/auth/gmail.readonly'),
    $key
);
$client->setAssertionCredentials($cred);
if($client->getAuth()->isAccessTokenExpired()) {
  $client->getAuth()->refreshTokenWithAssertion($cred);
}

This returns the following message: 这将返回以下消息:

Error refreshing the OAuth2 token, message: '{ "error" : "invalid_grant" }'' 刷新OAuth2令牌时出错,消息:'{“error”:“invalid_grant”}''

After tracking this code to it's source, which can be found in Google/Auth/OAuth2.php 跟踪此代码后,可以在Google/Auth/OAuth2.php找到该代码

The method in question, refreshTokenRequest : 有问题的方法, refreshTokenRequest

private function refreshTokenRequest($params)
{
    $http = new Google_Http_Request(
    self::OAUTH2_TOKEN_URI,
    'POST',
    array(),
    $params
    );
    $http->disableGzip();
    $request = $this->client->getIo()->makeRequest($http);

    $code = $request->getResponseHttpCode();
    $body = $request->getResponseBody();
    if (200 == $code) {
      $token = json_decode($body, true);
      if ($token == null) {
        throw new Google_Auth_Exception("Could not json decode the access token");
      }

      if (! isset($token['access_token']) || ! isset($token['expires_in']))     {
        throw new Google_Auth_Exception("Invalid token format");
      }

      if (isset($token['id_token'])) {
        $this->token['id_token'] = $token['id_token'];
      }
      $this->token['access_token'] = $token['access_token'];
      $this->token['expires_in'] = $token['expires_in'];
      $this->token['created'] = time();
    } else {
      throw new Google_Auth_Exception("Error refreshing the OAuth2 token, message: '$body'", $code);
    }
  }

Which means that the $code variable is NULL. 这意味着$code变量为NULL。 I found this post on SO: 我在SO上发现了这篇文章:

Error refreshing the OAuth2 token { “error” : “invalid_grant” } 刷新OAuth2令牌时出错{“error”:“invalid_grant”}

And can see that there is still no prefered solution. 并且可以看出仍然没有首选解决方案。 This is driving me nuts. 这让我疯了。 There is very little to no documentation available on this and if anybody has a solution, I'm sure I'm not the only one looking for it. 目前很少甚至没有相关的文档,如果有人有解决方案,我相信我不是唯一一个寻找它的人。

Each access_token expires after a few seconds and need to be refreshed by refresh_token, "Offline access" is what you are looking for. 每个access_token在几秒钟后过期,需要刷新刷新,“离线访问”就是你要找的东西。 Here you can follow the documentation: 在这里你可以按照文档:

https://developers.google.com/accounts/docs/OAuth2WebServer#offline https://developers.google.com/accounts/docs/OAuth2WebServer#offline

To obtain a refresh_token you have to run this code only one time: 要获取refresh_token,您只需运行此代码一次:

require_once 'Google/Client.php';

$client = new Google_Client();
$client->setClientId('{MY_CLIENT_ID}.apps.googleusercontent.com');
$client->setClientSecret('{MY_KEY}');
$client->setRedirectUri('{MY_REDIRECT_URI}');
//next two line added to obtain refresh_token
$client->setAccessType('offline');
$client->setApprovalPrompt('force');
$client->setScopes(array('https://www.googleapis.com/auth/gmail.readonly'));

if (isset($_GET['code'])) {
    $credentials = $client->authenticate($_GET['code']);  

    /*TODO: Store $credentials somewhere secure */

} else {
    $authUrl = $client->createAuthUrl();
    print "<a class='login' href='$authUrl'>Connect Me!</a>";
}

$credentials includes an access token and a refresh token. $credentials包括访问令牌和刷新令牌。 You have to store this to obtain new access tokens at any time. 您必须存储此信息才能随时获取新的访问令牌。 So when you wanted to make a call to api: 所以,当你想打电话给api时:

require_once 'Google/Client.php';
require_once 'Google/Service/Gmail.php';

/*TODO: get stored $credentials */

$client = new Google_Client();
$client->setClientId('{MY_CLIENT_ID}.apps.googleusercontent.com');
$client->setRedirectUri('{MY_REDIRECT_URI}');
$client->setClientSecret('{MY_KEY}');
$client->setScopes(array('https://www.googleapis.com/auth/gmail.readonly'));
$client->setAccessToken($credentials);

$service = new Google_Service_Gmail($client);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM