Google 身份验证令牌返回不包含刷新令牌

hun*_*dev 4 javascript google-api node.js google-oauth google-api-nodejs-client

我写了一个关于 google api 使用的例子。谷歌 NodeJS 客户端库。我已遵循指令集access_type : 'offline',但是对象返回不包含refresh_token.

我的代码:

var http = require('http');
var express = require('express');
var Session = require('express-session');
var google = require('googleapis');
var plus = google.plus('v1');
var OAuth2 = google.auth.OAuth2;
const ClientId = "251872680446-rvkcvm5mjn1ps32iabf4i2611hcg086e.apps.googleusercontent.com";
const ClientSecret = "F1qG9fFS-QwcrEfZbT8VmUnx";
const RedirectionUrl = "http://localhost:8081/oauthCallback";

var app = express();
app.use(Session({
    secret: 'raysources-secret-19890913007',
    resave: true,
    saveUninitialized: true
}));

function getOAuthClient () {
    return new OAuth2(ClientId ,  ClientSecret, RedirectionUrl);
}

function getAuthUrl () {
    var oauth2Client = getOAuthClient();
    // generate a url that asks permissions for Google+ and Google Calendar scopes
    var scopes = [
      'https://www.googleapis.com/auth/plus.me'
    ];

    var url = oauth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: scopes // If you only need one scope you can pass it as string
    });

    return url;
}

app.use("/oauthCallback", function (req, res) {
    var oauth2Client = getOAuthClient();
    var session = req.session;
    var code = req.query.code;
    oauth2Client.getToken(code, function(err, tokens) {
        console.log("tokens : ", tokens); 
          // Now tokens contains an access_token and an optional refresh_token. Save them.
          if(!err) {
            oauth2Client.setCredentials(tokens);
            session["tokens"]=tokens;
            res.send(`
                <html>
                <body>
                    <h3>Login successful!!</h3>
                    <a href="/details">Go to details page</a>
                <body>
                <html>
            `);
          }
          else{
            res.send(`
                <html>
                <body>
                    <h3>Login failed!!</h3>
                </body>
                </html>
            `);
          }
    });
});

app.use("/details", function (req, res) {
    var oauth2Client = getOAuthClient();
    oauth2Client.setCredentials(req.session["tokens"]);

    var p = new Promise(function (resolve, reject) {
        plus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) {
            console.log("response : " , response);
            resolve(response || err);
        });
    }).then(function (data) {
        res.send(`<html><body>
            <img src=${data.image.url} />
            <h3>Hello ${data.displayName}</h3>
            </body>
            </html>
        `);
    })
});

app.use("/", function (req, res) {
    var url = getAuthUrl();
    res.send(`
        <html>
        <body>
<h1>Authentication using google oAuth</h1>
        <a href=${url}>Login</a>
        </body>
        </html>
    `)
});


var port = 8081;
var server = http.createServer(app);
server.listen(port);
server.on('listening', function () {
    console.log(`listening to ${port}`);
});
Run Code Online (Sandbox Code Playgroud)

Ber*_*tel 5

仅当用户在批准您指定的范围后首次登录您的应用程序时,才会发送刷新令牌。

编辑 08/2018:使用approval_prompt:'force'不再有效,你需要使用prompt:'consent'(检查@Alexander的答案)

如果您想在每次用户登录时获取刷新令牌(即使用户之前已经登录并批准了范围),您必须prompt:'consent'Oauth2Client配置中指定:

var url = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: scopes,
    prompt : 'consent'
});
Run Code Online (Sandbox Code Playgroud)

请注意,这将要求用户每次单击您的链接进行身份验证时接受指定的范围:

在此输入图像描述

您还可以在帐户权限设置中手动禁用该应用程序,这将撤销该应用程序,并且用户将必须再次接受范围,这将在refresh_token您下次进行身份验证时触发发送:

在此输入图像描述

仅供参考,如果您需要access_token离线使用,则必须存储服务器端,并在从 Google API 收到状态 401 时refresh_token刷新存储的 access_token 。refresh_token因此,如果您refresh_token按照应有的方式存储,实际上无需在prompt:'consent'用户每次连接到您的应用程序时使用并强制用户批准范围。