You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Node.js程序获取Google ID Token调用认证后的AppScript API

如何从Node.js服务获取Google ID Token以调用需认证的Apps Script Web App

问题描述

我需要获取ID Token来访问要求本人账号认证的Google Apps Script Web App,最终要实现getGoogleIDTokenToInvokeAppScriptEndPoint函数。具体要怎么从外部Node.js服务程序化获取这个Token?我不想用服务账号,只想用自己的Google账号(abc@gmail.com)来获取Token,之后用它调用我的Apps Script服务。

我已经完成的操作:

  • 创建了doPost请求并完成部署,当前接口仅能携带Bearer格式的ID Token时被调用。

期望实现的Node.js代码示例:

// External Script from where I am invoking AppScript API
const token = getGoogleIDTokenToInvokeAppScriptEndPoint();
// Now Since I got my ID Token, I could use the same
// to invoke my appScript app:
fetch(appScriptEndpoint, 
    {
    method:"POST",
    headers: {
        Authorization: `Bearer ${token}` // Token I got from first step
    }
}).then(res => res.json().then(data => data))

我的Apps Script代码(供参考):

// AppScript Script
const doPost = (request = {}) => {
    const { _, postData: { contents, type } = {} } = request;
    let query = {};
    if (type === 'application/json') {
        query = JSON.parse(contents);
    } else if (type === 'application/x-www-form-urlencoded') {
        contents
            .split('&')
            .map((input) => input.split('='))
            .forEach(([key, value]) => {
                query[decodeURIComponent(key)] = decodeURIComponent(value);
            });
    } else if (type === 'text/plain') {
        try {
            query = JSON.parse(contents);
        } catch (e) {
            return ContentService.createTextOutput(
                JSON.stringify({
                    "error": true,
                    "statusCode": 400,
                    "msg": 'Unable to Parse JSON',
                    "type": type,
                    "requestBody": contents,
                    "payload": {}
                })
            ).setMimeType(ContentService.MimeType.JSON);
        }
    } else
        return ContentService.createTextOutput(
            JSON.stringify({
                "error": true,
                "statusCode": 400,
                "msg": 'Unknown Request Type',
                "type": type,
                "requestBody": contents,
                "payload": {}
            })
        ).setMimeType(ContentService.MimeType.JSON);

    const apiKey = query.apiKey;
    const isAuthenticated = authenticate({apiKey});
    if(!isAuthenticated) return ContentService.createTextOutput(
            JSON.stringify({
                "error": true,
                "statusCode": 401,
                "msg": 'User not authorized to make the Request.',
                "type": type,
                "requestBody": contents,
                "payload": {}
            })
        ).setMimeType(ContentService.MimeType.JSON);
    else {
        const {opType,opProps} = query;
        const result = requestHandler({opType, opProps});
        return ContentService.createTextOutput(
            JSON.stringify({
                "error": false,
                "statusCode": 200,
                "msg": 'Connection Established',
                "type": type,
                "requestBody": contents,
                "payload": result
            })
        ).setMimeType(ContentService.MimeType.JSON);
    }
};

解决方案步骤

1. 创建OAuth 2.0桌面客户端凭据

  • 进入Google Cloud控制台,选择对应项目(无项目则新建)
  • 导航到「API和服务」→「凭据」
  • 点击「创建凭据」→「OAuth客户端ID」
  • 应用类型选「桌面应用」,填写名称后完成创建
  • 下载生成的credentials.json,保存到Node.js项目目录

2. 安装依赖

在Node.js项目中执行:

npm install google-auth-library

3. 实现Token获取函数

核心逻辑是通过OAuth 2.0授权码流获取ID Token,指定Apps Script Web App的客户端ID作为受众。完整代码如下:

const { OAuth2Client } = require('google-auth-library');
const fs = require('fs');
const path = require('path');

// 配置参数
const CREDENTIALS_PATH = path.join(__dirname, 'credentials.json');
// 替换为你的Apps Script Web App客户端ID(格式:{部署ID}.apps.googleusercontent.com)
const APPS_SCRIPT_CLIENT_ID = '你的Apps Script客户端ID';
const TOKEN_PATH = path.join(__dirname, 'token.json');

async function getGoogleIDTokenToInvokeAppScriptEndPoint() {
  const oAuth2Client = new OAuth2Client();
  
  // 加载客户端凭据
  const credentials = JSON.parse(fs.readFileSync(CREDENTIALS_PATH));
  const { client_secret, client_id, redirect_uris } = credentials.installed;
  oAuth2Client.setCredentials({ client_id, client_secret, redirect_uri: redirect_uris[0] });

  // 读取缓存token或发起授权流程
  let token;
  try {
    token = JSON.parse(fs.readFileSync(TOKEN_PATH));
    oAuth2Client.setCredentials(token);
    
    // 自动刷新过期token
    if (oAuth2Client.isTokenExpiring()) {
      const refreshedToken = await oAuth2Client.refreshAccessToken();
      token = refreshedToken.credentials;
      fs.writeFileSync(TOKEN_PATH, JSON.stringify(token));
    }
  } catch (err) {
    token = await getAccessToken(oAuth2Client);
    fs.writeFileSync(TOKEN_PATH, JSON.stringify(token));
  }

  // 获取针对Apps Script的ID Token
  const idToken = await oAuth2Client.getIdToken(APPS_SCRIPT_CLIENT_ID);
  return idToken;
}

// 首次授权流程
async function getAccessToken(oAuth2Client) {
  const authUrl = oAuth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: ['openid', 'email', 'profile'],
  });
  console.log('请访问以下链接授权:', authUrl);
  
  const readline = require('readline').createInterface({
    input: process.stdin,
    output: process.stdout,
  });
  
  return new Promise((resolve) => {
    readline.question('输入页面返回的授权码: ', (code) => {
      readline.close();
      oAuth2Client.getToken(code).then(({ tokens }) => resolve(tokens));
    });
  });
}

// 测试调用示例
async function testCallAppScript() {
  const appScriptEndpoint = '你的Apps Script Web App部署URL';
  const token = await getGoogleIDTokenToInvokeAppScriptEndPoint();
  
  const response = await fetch(appScriptEndpoint, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ apiKey: '你的API密钥', opType: 'xxx', opProps: {} })
  });
  
  const data = await response.json();
  console.log(data);
}

testCallAppScript();

4. 获取Apps Script Web App客户端ID

  • 打开Apps Script项目,点击「部署」→「管理部署」
  • 找到目标部署,点击「编辑」查看部署ID
  • 客户端ID格式为{部署ID}.apps.googleusercontent.com,也可在Google Cloud控制台的「OAuth同意屏幕」中确认

关键注意事项

  • 首次授权:第一次运行代码会输出授权URL,用abc@gmail.com登录授权后输入返回的代码,token会缓存到token.json,后续无需重复授权
  • Token有效期:ID Token有效期1小时,代码已实现自动刷新逻辑
  • OAuth同意屏幕配置:个人账号需在Google Cloud控制台的OAuth同意屏幕中添加abc@gmail.com为测试用户,否则会触发授权错误
  • Web App权限:确保部署时选择「仅限我自己」或「组织内用户」,且开启「需要授权」选项

内容的提问来源于stack exchange,提问作者Shivam Sahil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 14:40:07