在首次自动使用后维护 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 。
在文档中提及这也可能很有用,
除非是,我只是错过了这个细节。
之前曾为 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 。 在文档中提及这也可能很有用, 除非是,我只是错过了这个细节。