在首次自动使用后维护 google 客户端 API refresh_token

Maintaining google client API refresh_token beyond first automatic usage

之前曾为 google api 维护过 OAuth2 refresh_token 的人,我可以与您比较代码吗? 文档说如果我用 access_type:"offline" 创建一个 access_token, 客户端 api 将在到期前自动使用 refresh_token, 但就我而言,这只会发生一次, 此时 refresh_token 从更新的令牌对象中消失。 我的代码就这么简单:

async function google(request)
{let [{google},keys]=await Promise.all(
[import("./node_modules/googleapis/build/src/index.js")
,import("./keys.json").then(json=>json.default)
]);
 let {client,secret,token}=keys;
 let authority=new google.auth.OAuth2(client,secret,request.url);
 authority.on('tokens',token=>save("keys.json",{...keys,token}).then(console.log));
 if(!token)
 if(!request.query.code)
 return authority.generateAuthUrl({scope,access_type:"offline",prompt:"consent"});
 else return new Promise(resolve=>
 authority.getToken(request.query.code,resolve)).then(fail=>fail||"new access_token");
 authority.setCredentials(token);
 google=google.sheets({version:"v4",auth:authority});
 return new Promise(resolve=>
 google.spreadsheets.values.get(sheet,resolve)).then(fail=>fail||"valid token");
 // first return value: [consent url redirecting to the same endpoint]
 // after using the url: "new access_token"
 // during the next 2 hours: "valid token" ("refresh_token" gone missing from keys.json in the second hour)
 // after 2 hours: "Error: missing required parameter: refresh_token"
}

可能是因为我在每次请求时动态重新实例化 API? 我也每次都设置凭据, 所以静态 API

应该没什么区别

这是我手头最好的例子,它使用了不同的 API 但应该会给你一个想法。

图书馆不为您保存或加载。但是它确实支持您将刷新令牌加载到其中。所以只要你把它保存在某个地方然后在正确的时间加载它就可以了。

检查我如何使用 TOKEN_PATH 这是存储令牌的路径。当代码首次运行时,系统将尝试读取该文件并加载存储在其中的任何令牌。

注意刷新令牌只会在第一次返回给您,如果您需要它,您需要保存它。不要不小心用 null 覆盖它。

阅读我中有很多关于如何设置的信息。 Google api node.js client

const fs = require('fs');
const readline = require('readline');
const {google} = require('googleapis');
const dotenv = require('dotenv');
dotenv.config();
const CRED_FILE_PATH = process.env.API_CREDS;
console.log(`Your cred path is ${CRED_FILE_PATH}`); // ../creds.json
const VIEW_ID = process.env.VIEW_ID;
console.log(`Your view id is ${VIEW_ID}`);

// If modifying these scopes, delete token.json.
const SCOPES = ['https://www.googleapis.com/auth/analytics.readonly'];
// The file token.json stores the user's access and refresh tokens, and is
// created automatically when the authorization flow completes for the first
// time.
const TOKEN_PATH = 'token.json';

// Load client secrets from a local file.
fs.readFile(CRED_FILE_PATH, (err, content) => {
    if (err) return console.log('Error loading client secret file:', err);
    // Authorize a client with credentials, then call the Google Drive API.
    authorize(JSON.parse(content), getUserReport);
});

/**
 * Create an OAuth2 client with the given credentials, and then execute the
 * given callback function.
 * @param {Object} credentials The authorization client credentials.
 * @param {function} callback The callback to call with the authorized client.
 */
function authorize(credentials, callback) {
    const {client_secret, client_id, redirect_uris} = credentials.installed;
    const oAuth2Client = new google.auth.OAuth2(
        client_id, client_secret, redirect_uris[0]);

    // Check if we have previously stored a token.
    fs.readFile(TOKEN_PATH, (err, token) => {
        if (err) return getAccessToken(oAuth2Client, callback);
        oAuth2Client.setCredentials(JSON.parse(token));
        callback(oAuth2Client);
    });
}

/**
 * Get and store new token after prompting for user authorization, and then
 * execute the given callback with the authorized OAuth2 client.
 * @param {google.auth.OAuth2} oAuth2Client The OAuth2 client to get token for.
 * @param {getEventsCallback} callback The callback for the authorized client.
 */
function getAccessToken(oAuth2Client, callback) {
    const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: SCOPES,
    });
    console.log('Authorize this app by visiting this url:', authUrl);
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
    });
    rl.question('Enter the code from that page here: ', (code) => {
        rl.close();
        oAuth2Client.getToken(code, (err, token) => {
            if (err) return console.error('Error retrieving access token', err);
            oAuth2Client.setCredentials(token);
            // Store the token to disk for later program executions
            fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
                if (err) return console.error(err);
                console.log('Token stored to', TOKEN_PATH);
            });
            callback(oAuth2Client);
        });
    });
}

我对 DalmTo 的回答的评论证明是答案: access_token 的 refresh_token 是静态的,所以问题是 保存新令牌时,必须保留 refresh_token 。 在文档中提及这也可能很有用, 除非是,我只是错过了这个细节。