如何使用Apps Script OAuth2库实现令牌自动刷新?
可以实现令牌过期自动刷新,无需重复授权。你的代码框架没问题,但时间触发器运行时认证失败,大概率是以下几个原因导致的:
1. 未正确获取并存储refresh_token
谷歌OAuth2默认情况下,只有首次授权Web应用类型的客户端时会返回refresh_token,后续重复授权(无prompt=consent参数)不会再返回。如果你的应用没有拿到refresh_token,自然无法自动刷新令牌。
解决办法:
在创建OAuth2服务时添加强制获取refresh_token的参数:
return OAuth2.createService('myService') .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth') .setTokenUrl('https://oauth2.googleapis.com/token') .setClientId(credentials.web.client_id) .setClientSecret(credentials.web.client_secret) .setCallbackFunction('authCallback') .setPropertyStore(PropertiesService.getUserProperties()) .setCache(CacheService.getUserCache()) .setLock(LockService.getUserLock()) .setScope('https://www.googleapis.com/auth/drive') .setParam('prompt', 'consent'); // 新增这一行,强制返回refresh_token
添加后重新手动授权一次,确保refresh_token被存入用户属性存储中。之后可以根据需求移除这个参数(避免每次授权都弹出同意页面)。
2. 时间触发器的运行身份不匹配
你使用的PropertiesService.getUserProperties()是当前授权用户专属的属性存储,如果时间触发器的运行身份不是授权应用的用户,就无法读取到令牌信息,导致认证失败。
解决办法:
创建时间触发器时,选择**“以我身份运行”**(默认选项),确保触发器执行时使用的是授权过应用的用户身份,而非其他用户身份。
3. 触发器执行代码未检查令牌有效性
在调用API之前,必须调用service.hasAccess()方法——这个方法会自动检查当前令牌是否过期,如果过期且存在有效refresh_token,会自动刷新令牌并将新令牌保存到属性存储中。如果跳过这一步直接调用API,就会遇到过期令牌导致的认证错误。
示例正确的触发器执行代码:
function triggerTask() { // 获取你的OAuth2服务实例 const service = getMyOAuthService(); // 检查令牌有效性,自动刷新过期令牌 if (!service.hasAccess()) { throw new Error('无法获取有效令牌,请先手动完成应用授权'); } // 调用API示例(以Drive API为例) const apiUrl = 'https://www.googleapis.com/drive/v3/files?pageSize=10'; const response = UrlFetchApp.fetch(apiUrl, { headers: { 'Authorization': `Bearer ${service.getAccessToken()}` } }); // 处理API响应 console.log(response.getContentText()); }
4. 客户端ID配置错误
确认你的客户端ID是在Google Cloud Console中创建的**“Web应用”类型**,并且已将Apps Script的回调URI添加到授权重定向URI列表中。回调URI格式为:https://script.google.com/macros/d/你的脚本ID/usercallback
(脚本ID可在Apps Script编辑器的“项目设置”中找到)
完成以上调整后,时间触发器应该就能自动刷新令牌,无需重复授权。
内容的提问来源于stack exchange,提问作者Utsab Subedi

