从Cloud Function调用Apps Script API时出现403权限错误
Workspace插件后台任务流程中无权限用户触发403错误的解决
问题背景
我正在开发一款可从Google Drive启动、以后台任务形式运行的Workspace插件。实现逻辑为:Apps Script插件调用Google Cloud Function(GCF),再由GCF通过Apps Script API回调Apps Script(因流程耗时较长)。
已声明的OAuth权限范围
"oauthScopes": [ "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/drive.addons.metadata.readonly", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/script.scriptapp" ],
流程步骤
- 用户打开插件,授予上述权限范围的访问权限;
- 用户选择要处理的Google Drive文件并点击按钮;
- Apps Script调用GCF,同时发送用户的OAuth令牌;
- GCF以该OAuth令牌为身份验证载体,通过Apps Script API调用我的Apps Script函数;
- 核心问题:无GCP项目及Apps Script项目权限的用户尝试使用插件时,触发403错误。
环境与配置信息
- Apps Script与GCF位于同一GCP项目,已启用Apps Script API;
- Apps Script项目已部署为Workspace插件(正在接受Marketplace团队审核),仅我拥有访问权限;
- 使用服务账户身份令牌从Apps Script调用GCF;
- 尝试使用已授权用户的OAuth令牌从GCF回调Apps Script;
- 清单中设置了
"executionAPI access: anyone",但不确定是否生效; - 测试验证:Apps Script项目编辑者账户可正常运行流程,仅读者权限或无权限的账户失败,说明GCF回调时使用的Bearer令牌不足以授权账户。
相关代码
Apps Script调用GCF的代码
const userToken = ScriptApp.getOAuthToken(); const resp = UrlFetchApp.fetch(BACKGROUND_GCF_URL + '?userToken=' + userToken + '&fileId=' + fileId + '&execUid=' + execUid, { headers: { Authorization: 'Bearer ' + bearer // 服务账户生成的身份令牌 }, muteHttpExceptions: true })
GCF调用Apps Script API的代码
const body = { function: 'receiveGCFcall', parameters: [ execUid, fileId, userToken ], devMode: true } const config = { headers: { Authorization: 'Bearer ' + userToken } } axios .post(URL, body, config) .then(resp => { console.log(`statusCode: ${resp.status}`); console.log(`data: ${JSON.stringify(resp.data)}`) if(resp.data.result === 'NOT OK') { console.error(`[${execUid}] Something went wrong, the slides have not been updated`) } }).catch(...) // 此处触发403错误
问题根源
当前使用用户OAuth令牌调用Apps Script API时,令牌仅能代表用户自身权限。对于无Apps Script项目权限的用户,即使已授予插件OAuth权限,也无法通过API执行该脚本——因为script.scriptapp权限仅允许用户操作自己创建或拥有权限的脚本,而非第三方插件的后台脚本。
解决方法
1. 使用服务账户进行API调用(推荐)
由于GCF和Apps Script同属一个GCP项目,可使用GCP服务账户(而非用户令牌)调用Apps Script API,确保调用身份拥有脚本执行权限:
- 给服务账户授予Apps Script项目的编辑者权限;
- 在GCF中使用服务账户生成的OAuth令牌(而非用户令牌)发起API调用;
- 若需操作用户的Drive文件,可通过**域范围授权(Domain-Wide Delegation)**让服务账户模拟用户身份执行操作(仅适用于Workspace域用户)。
2. 调整脚本执行权限配置
确保Apps Script项目的执行API权限正确设置:
- 在Apps Script编辑器中,进入项目设置 > 执行API访问权限,选择“任何人”或“任何人,甚至匿名”(根据需求选择);
- 确认清单文件中的
executionApi.access字段设置为"ANYONE":
"executionApi": { "access": "ANYONE" }
3. 移除devMode参数
当前代码中devMode: true仅允许脚本开发者执行API调用,需移除该参数,使用生产部署版本:
const body = { function: 'receiveGCFcall', parameters: [execUid, fileId, userToken] // 移除devMode字段 }
4. 补充用户令牌权限范围
确保用户令牌包含https://www.googleapis.com/auth/script.run权限(当前清单未声明),该权限允许用户通过API执行插件关联的脚本。更新OAuth权限范围:
"oauthScopes": [ // 原有权限... "https://www.googleapis.com/auth/script.run" ],
注意事项
- 若插件面向外部非Workspace域用户,域范围授权不可用,需确保脚本执行权限设置为“任何人”,并使用服务账户调用API;
- 提交Marketplace审核时,需明确说明各权限的使用目的,避免因权限范围过大被拒。
内容的提问来源于stack exchange,提问作者ValLeNain
相关产品推荐
相关产品推荐

