如何使用Google Refresh Token刷新Google Access Token(Firebase+Vue2场景)
Access Token刷新实现方案
前置配置校验(必须完成,否则无法获取有效Refresh Token)
首先确认你初始化GoogleAuthProvider时已配置必要参数,这是Google返回有效Refresh Token的前提:
- 必须设置
access_type: 'offline'参数 - 建议添加
prompt: 'consent'参数,避免用户已授权场景下Google不返回Refresh Token - 已在Google Cloud控制台为对应的OAuth 2.0客户端开启Calendar API权限,并在OAuth同意屏幕配置了日历相关权限范围(如
https://www.googleapis.com/auth/calendar.readonly)
Vue2端初始化Provider示例代码:
import firebase from 'firebase/app' import 'firebase/auth' const googleProvider = new firebase.auth.GoogleAuthProvider() // 添加日历访问权限 googleProvider.addScope('https://www.googleapis.com/auth/calendar.readonly') // 配置获取Refresh Token必须的参数 googleProvider.setCustomParameters({ access_type: 'offline', prompt: 'consent' })
用户登录成功后,将获取到的Refresh Token、Access Token、过期时间戳存储到对应位置:前端可临时存到localStorage,后端建议存到Firestore对应用户文档中。
方案1:前端直接刷新(适合内部小范围使用的应用)
当检测到Access Token即将过期(可提前5分钟判断,或调用Calendar API返回401状态码时),直接向Google OAuth端点发起请求刷新Token,代码示例:
/** * 刷新Google Access Token * @param {string} refreshToken 已存储的Refresh Token * @returns {object|null} 新的Token信息,刷新失败返回null */ async function refreshAccessToken(refreshToken) { const CLIENT_ID = '你的Google Cloud OAuth 2.0客户端ID' const CLIENT_SECRET = '你的Google Cloud OAuth 2.0客户端密钥' try { const response = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: CLIENT_ID, client_secret: CLIENT_SECRET, refresh_token: refreshToken, grant_type: 'refresh_token' }) }) const tokenInfo = await response.json() return { accessToken: tokenInfo.access_token, expiresAt: Date.now() + tokenInfo.expires_in * 1000 } } catch (error) { console.error('Token刷新失败', error) // 刷新失败引导用户重新登录授权 return null } }
注意:该方案需要将Client Secret放到前端代码中,存在泄露风险,公开面向用户的应用不建议使用。
方案2:Firebase云函数刷新(推荐,安全性更高)
将刷新逻辑放到Firebase云函数侧执行,避免泄露敏感信息,实现步骤如下:
2.1 编写云函数代码
const functions = require('firebase-functions') const admin = require('firebase-admin') const fetch = require('node-fetch') admin.initializeApp() exports.refreshGoogleToken = functions.https.onCall(async (data, context) => { // 校验用户登录状态 if (!context.auth) { throw new functions.https.HttpsError('unauthenticated', '未登录用户无法操作') } const userId = context.auth.uid // 从Firestore取出对应用户的Refresh Token const userDoc = await admin.firestore().collection('users').doc(userId).get() const refreshToken = userDoc.data().googleRefreshToken // 通过云函数配置读取敏感信息,不要硬编码 const clientId = functions.config().google.client_id const clientSecret = functions.config().google.client_secret const res = await fetch('https://oauth2.googleapis.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: clientId, client_secret: clientSecret, refresh_token: refreshToken, grant_type: 'refresh_token' }) }) const newTokenInfo = await res.json() // 将新的Token信息更新到Firestore await admin.firestore().collection('users').doc(userId).update({ googleAccessToken: newTokenInfo.access_token, googleTokenExpiresAt: Date.now() + newTokenInfo.expires_in * 1000 }) return { accessToken: newTokenInfo.access_token, expiresAt: Date.now() + newTokenInfo.expires_in * 1000 } })
2.2 前端Vue2调用云函数获取有效Token
/** * 获取可用的Google Access Token,自动处理过期刷新 * @returns {string} 可用的Access Token */ async function getValidAccessToken() { const currentUser = firebase.auth().currentUser if (!currentUser) throw new Error('用户未登录') // 读取当前存储的Token信息 const userDoc = await firebase.firestore().collection('users').doc(currentUser.uid).get() const { googleAccessToken, googleTokenExpiresAt } = userDoc.data() // 提前5分钟判断Token是否即将过期 if (Date.now() < googleTokenExpiresAt - 5 * 60 * 1000) { return googleAccessToken } // 过期则调用云函数刷新 const refreshResult = await firebase.functions().httpsCallable('refreshGoogleToken')() return refreshResult.data.accessToken }
注意事项
- Refresh Token只要用户没有主动取消授权、Google账号没有安全风险,就是长期有效的,无需定期刷新,只有当刷新请求返回
invalid_grant错误时,才需要引导用户重新登录授权 - 所有敏感信息(如Client Secret)不要硬编码到前端代码或者云函数代码中,建议通过Firebase云函数配置、环境变量存储
- 调用Calendar API时如果返回401状态码,直接触发刷新逻辑即可,无需完全依赖本地存储的过期时间判断
内容的提问来源于stack exchange,提问作者MVT KVM
相关产品推荐
相关产品推荐

