使用javascript的Google Oauth Cross-client身份验证:令牌已过期

时间:2014-11-10 02:40:38

标签: javascript php oauth google-api-php-client

我一整天都在处理这个问题,而我却无法弄清楚是什么问题。

我有一个使用Google Api客户端的应用程序用于javascript,它没有任何问题。现在我想在服务器端做一些事情,所以在研究了一下后,发现要走的路是在后端使用setAccessToken方法在客户端使用令牌。

所以我尝试将我的令牌对象作为JSON(使用JSON.stringify(gapi.auth.getToken()))发送,一旦我尝试在需要auth的后端进行API调用,我就会收到以下错误:

  

OAuth 2.0访问令牌已过期,并且刷新令牌不可用。对于自动批准的响应,不会返回刷新令牌。

所以,有点困惑,我尝试使用谷歌终端上的curl来解决令牌,这会返回以下内容

{
    "issued_to": "client_id",
    "audience": "client_id",
    "user_id": "user_id",
    "scope": "https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me",
    "expires_in": 1465,
    "email": "user_email",
    "verified_email": true,
    "access_type": "online"
}

所以我知道令牌很好而且有效。我的代码设置方式如下(编辑:

<?php
// The token JSON is not inline, it comes from another source directly from the client side, but this is how it looks
$token_json = '{"state":"","access_token":"TOTALLY_VALID_ACCESS_TOKEN","token_type":"Bearer","expires_in":"3600","scope":"https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/plus.me","client_id":"CLIENT_ID","g_user_cookie_policy":"single_host_origin","cookie_policy":"single_host_origin","response_type":"token","issued_at":"1415583001","expires_at":"1415586601","g-oauth-window":{},"status":{"google_logged_in":false,"signed_in":true,"method":"PROMPT"}}';

$OAUTH2_CLIENT_ID = 'CLIENT_ID';
$OAUTH2_CLIENT_SECRET = 'CLIENT_SECRET';

$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->setAccessToken($token_json);

$youtube = new Google_Service_YouTube($client);

try{

    /* Random code goes here */

    // Auth Exception here.
    $insertRequest = $youtube->videos->insert("status,snippet", $video);

} catch (Google_Exception $e) {
    var_dump($e->getMessage());
}   

我是否需要设置离线访问权限?我要求登录过程必须是javascript,因此无法从后端重新创建登录流程。

我有什么遗失的吗?

2 个答案:

答案 0 :(得分:3)

好吧,如果其他人偶然发现了这个:

显然,直接共享令牌不是可行的方法,因为不同的API包装器处理令牌的方式不同。您需要做的是将一次性代码传递给PHP并使用以下内容获取访问令牌

    $client = new Google_Client();
    $client->setClientId($OAUTH2_CLIENT_ID);
    $client->setClientSecret($OAUTH2_CLIENT_SECRET);

    // Couldn't find this anywhere in the docs, but it's required. If you don't pass this, you will get an Origin Mismatch error.
    $client->setRedirectUri('postmessage'); 

    // Get this from javascript
    $client->authenticate($ONE_TIME_CODE);

    // Optionally, you might want to retrieve the token and save it somewhere else e.g. the session, as the code is only good for a single use.         
    $_SESSION['token'] = $client->getAccessToken(); 

另外,从JS你需要指定除了JS令牌之外你还需要这个一次性代码,我在其他任何地方都找不到它。

gapi.auth.authorize

的示例设置
{
        client_id: CLIENT_ID
        scope: APP_SCOPES
        cookie_policy: 'single_host_origin'
        response_type: 'code token'
        immediate: true
}

答案 1 :(得分:0)

非常感谢,Moustached。我也花了一整天的时间来解决这个问题。但是,我发现不是那么明显什么是一次性代码以及如何获得它,所以我决定在这里提供我的代码以防其他人遇到同样的问题:

<html>
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
        <script src="https://apis.google.com/js/platform.js?onload=onGoogleAPILoad" async defer></script>
        <script>
            $(document).ready(function() {
                var auth2;

                window.onGoogleAPILoad = function() {
                    gapi.load('auth2', function() {
                        auth2 = gapi.auth2.init({ client_id: 'CLIENT_ID', scope: 'profile' });
                    });
                };

                $('button').on('click', function() {
                    auth2.grantOfflineAccess({'redirect_uri': 'postmessage'}).then(function(response) {
                        $.ajax({
                            method: 'POST',
                            url: '/auth/signin',
                            success: onAuthSuccess = function(response) {
                                // check response from your server and reload page if succeed
                            },
                            data: { code: response.code }
                        });
                    });
                });
            });
        </script>
    </head>
    <body>
        <button>Sign In</button>
    </body>
</html>

对于后端,代码几乎相同:

$client = new Google_Client();
$client->setClientId('CLIENT_ID');
$client->setClientSecret('CLIENT_SECRET');
$client->setRedirectUri('postmessage'); 

$client->authenticate($code); // here is one-time code

$plus = new Google_Service_Plus($client);
$user = $plus->people->get('me');
// $user is in array, containing now id, name, etc.

这是关于该主题的article