如何使用 firebase 函数刷新 google oauth2 上的令牌?
how to refresh token on google oauth2 using firebase functions?
我在 firebase 函数中使用 Google Oauth2 开发了一个集成来访问 Google 表格 API。集成工作正常,但我在确保刷新令牌 运行 正确时遇到问题。该函数在第一个令牌过期后停止工作。
发生这种情况时会出现以下错误:
Function execution started
Error: No refresh token is set.
at OAuth2Client.refreshTokenNoCache (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:161:19)
at OAuth2Client.refreshToken (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:142:25)
at OAuth2Client.getRequestMetadataAsync (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:256:28)
at OAuth2Client.requestAsync (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:329:34)
at OAuth2Client.request (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:323:25)
at createAPIRequestAsync (/workspace/node_modules/googleapis-common/build/src/apirequest.js:292:27)
at Object.createAPIRequest (/workspace/node_modules/googleapis-common/build/src/apirequest.js:43:9)
at Resource$Spreadsheets$Values.update (/workspace/node_modules/googleapis/build/src/apis/sheets/v4.js:601:37)
at exports.loadStripeData.functions.runWith.https.onRequest (/workspace/index.js:176:32)
at process._tickCallback (internal/process/next_tick.js:68:7)
我想确保令牌正确刷新并存储在 Firestore 上。
我做错了什么?
index.js:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {google} = require('googleapis');
const sheets = google.sheets('v4');
admin.initializeApp();
const CLIENT_ID = 'CLIENT_ID';
const CLIENT_SECRET = 'CLIENT_SECRETT';
const REDIRECT_URL = 'https://us-central1-MY-PROJECT.cloudfunctions.net/oauth2callback';
const SCOPES = ['https://www.googleapis.com/auth/spreadsheets'];
oauth2Client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
try {
admin.firestore()
.collection('oauth2')
.doc('google')
.set({
tokens: tokens.refresh_token,
});
} catch (error) {
console.error(JSON.stringify(error));
}
}
});
/*asks user permission to access his spreadsheets*/
exports.authenticate = functions.https.onRequest((req, res) => {
const authorizeUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES.join(','),
});
res.send(`<html>click here: <a href="${authorizeUrl}">${authorizeUrl}</a></html>`)
});
/*callback function for when the user finishes authenticating*/
exports.oauth2callback = functions.https.onRequest(async(req, res) => {
const code = req.query.code.toString() || '';
try {
await admin.firestore()
.collection('oauth2')
.doc('google')
.set({
code: decodeURIComponent(code)
});
} catch(error) {
res.send(JSON.stringify(error))
}
res.send('auth successfully. You can close this tab');
});
/* get token from Firestone to execute function*/
async function oauth2Auth() {
const doc = await admin.firestore()
.collection('oauth2')
.doc('google')
.get();
const credentials = doc.data();
if (credentials.code !== undefined) {
const response = await oauth2Client.getToken(credentials.code);
credentials.tokens = response.tokens;
delete credentials.code;
try {
await admin.firestore()
.collection('oauth2')
.doc('google')
.set({
tokens: credentials.tokens,
})
} catch (error) {
console.error(error);
}
}
oauth2Client.setCredentials(credentials.tokens);
}
/*function that requires google sheets api*/
exports.mainFunction = functions.https.onRequest(async(req, res) => {
oauth2Auth();
//do main function
});
终于发现问题了!
您只会在第一次请求授权时获得刷新令牌。所以如果你没有正确保存它,你必须再次请求许可。
求解:
将用户重定向到授权时 URL 添加以下参数以确保您获得刷新令牌:
access_type=offline&prompt=consent
保存刷新令牌:
oauth2Client.on('tokens', async(tokens:any) => {
if (tokens.refresh_token) {
try {
const authorization = await oauth2Client.getToken(tokens.refresh_token);
await admin.firestore()
.collection('collectionName')
.doc(docId)
.update({
token: authorization.tokens
})
} catch (error) {
console.error(JSON.stringify(error));
}
}
});
我在 firebase 函数中使用 Google Oauth2 开发了一个集成来访问 Google 表格 API。集成工作正常,但我在确保刷新令牌 运行 正确时遇到问题。该函数在第一个令牌过期后停止工作。
发生这种情况时会出现以下错误:
Function execution started
Error: No refresh token is set.
at OAuth2Client.refreshTokenNoCache (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:161:19)
at OAuth2Client.refreshToken (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:142:25)
at OAuth2Client.getRequestMetadataAsync (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:256:28)
at OAuth2Client.requestAsync (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:329:34)
at OAuth2Client.request (/workspace/node_modules/googleapis-common/node_modules/google-auth-library/build/src/auth/oauth2client.js:323:25)
at createAPIRequestAsync (/workspace/node_modules/googleapis-common/build/src/apirequest.js:292:27)
at Object.createAPIRequest (/workspace/node_modules/googleapis-common/build/src/apirequest.js:43:9)
at Resource$Spreadsheets$Values.update (/workspace/node_modules/googleapis/build/src/apis/sheets/v4.js:601:37)
at exports.loadStripeData.functions.runWith.https.onRequest (/workspace/index.js:176:32)
at process._tickCallback (internal/process/next_tick.js:68:7)
我想确保令牌正确刷新并存储在 Firestore 上。
我做错了什么?
index.js:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {google} = require('googleapis');
const sheets = google.sheets('v4');
admin.initializeApp();
const CLIENT_ID = 'CLIENT_ID';
const CLIENT_SECRET = 'CLIENT_SECRETT';
const REDIRECT_URL = 'https://us-central1-MY-PROJECT.cloudfunctions.net/oauth2callback';
const SCOPES = ['https://www.googleapis.com/auth/spreadsheets'];
oauth2Client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
try {
admin.firestore()
.collection('oauth2')
.doc('google')
.set({
tokens: tokens.refresh_token,
});
} catch (error) {
console.error(JSON.stringify(error));
}
}
});
/*asks user permission to access his spreadsheets*/
exports.authenticate = functions.https.onRequest((req, res) => {
const authorizeUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: SCOPES.join(','),
});
res.send(`<html>click here: <a href="${authorizeUrl}">${authorizeUrl}</a></html>`)
});
/*callback function for when the user finishes authenticating*/
exports.oauth2callback = functions.https.onRequest(async(req, res) => {
const code = req.query.code.toString() || '';
try {
await admin.firestore()
.collection('oauth2')
.doc('google')
.set({
code: decodeURIComponent(code)
});
} catch(error) {
res.send(JSON.stringify(error))
}
res.send('auth successfully. You can close this tab');
});
/* get token from Firestone to execute function*/
async function oauth2Auth() {
const doc = await admin.firestore()
.collection('oauth2')
.doc('google')
.get();
const credentials = doc.data();
if (credentials.code !== undefined) {
const response = await oauth2Client.getToken(credentials.code);
credentials.tokens = response.tokens;
delete credentials.code;
try {
await admin.firestore()
.collection('oauth2')
.doc('google')
.set({
tokens: credentials.tokens,
})
} catch (error) {
console.error(error);
}
}
oauth2Client.setCredentials(credentials.tokens);
}
/*function that requires google sheets api*/
exports.mainFunction = functions.https.onRequest(async(req, res) => {
oauth2Auth();
//do main function
});
终于发现问题了!
您只会在第一次请求授权时获得刷新令牌。所以如果你没有正确保存它,你必须再次请求许可。
求解:
将用户重定向到授权时 URL 添加以下参数以确保您获得刷新令牌:
access_type=offline&prompt=consent
保存刷新令牌:
oauth2Client.on('tokens', async(tokens:any) => {
if (tokens.refresh_token) {
try {
const authorization = await oauth2Client.getToken(tokens.refresh_token);
await admin.firestore()
.collection('collectionName')
.doc(docId)
.update({
token: authorization.tokens
})
} catch (error) {
console.error(JSON.stringify(error));
}
}
});