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

求助:Google Apps Script中Firebase服务账户生成的认证令牌无效

解决Google Apps Script中用服务账号生成Firebase客户端认证令牌的问题

我完全懂你现在的困境——用服务账号生成的令牌在客户端验证时总是弹出INVALID_TOKEN: Failed to validate MAC错误,只有已经废弃的database secret能正常工作。这其实是因为FirebaseApp/GSApp这类第三方库的createAuthToken方法,在传入OAuth access token时并没有按照Firebase自定义令牌的要求正确签名,而是沿用了database secret的HMAC签名逻辑,才导致客户端验证失败。

下面是直接可行的解决方案:手动生成符合Firebase规范的JWT自定义令牌,用服务账号的私钥进行RS256签名,彻底摆脱对第三方库的依赖。

具体步骤与代码实现

1. 替换原有的makeToken函数

删掉你原来的makeToken,改用下面的代码直接生成合规的Firebase自定义令牌:

function makeToken() {
  const serviceEmail = fb_SERVICE_EMAIL; // 你的服务账号邮箱
  const privateKey = fb_PRIVATE_KEY.replace(/\\n/g, '\n'); // 注意处理私钥里的转义换行符
  const userEmail = Session.getActiveUser().getEmail();
  const uid = userEmail; // 可以用用户邮箱作为唯一标识,也可以自定义其他uid

  // 1. 构造JWT头部,固定RS256签名算法
  const header = JSON.stringify({
    alg: 'RS256',
    typ: 'JWT'
  });

  // 2. 构造JWT负载,必须包含Firebase要求的字段
  const now = Math.floor(Date.now() / 1000);
  const payload = JSON.stringify({
    iss: serviceEmail,
    sub: serviceEmail,
    aud: 'https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit',
    iat: now,
    exp: now + 3600, // 过期时间最长1小时,不能超过这个值
    uid: uid,
    email: userEmail,
    email_verified: true // 根据你的业务需求设置,这里默认用户已验证邮箱
  });

  // 3. 对头部和负载进行Base64URL编码
  const encodedHeader = Utilities.base64EncodeWebSafe(header);
  const encodedPayload = Utilities.base64EncodeWebSafe(payload);

  // 4. 用服务账号私钥进行RS256签名
  const signatureInput = `${encodedHeader}.${encodedPayload}`;
  const signatureBytes = Utilities.computeRsaSha256Signature(signatureInput, privateKey);
  const encodedSignature = Utilities.base64EncodeWebSafe(signatureBytes);

  // 5. 拼接成最终的认证令牌
  return `${encodedHeader}.${encodedPayload}.${encodedSignature}`;
}

2. 保留原有的客户端认证代码

你的客户端代码不需要做任何修改,直接使用这个新生成的令牌即可:

var userAuthToken;
google.script.run.withSuccessHandler(function (requestAuthToken) {
  userAuthToken = authenticateClient(requestAuthToken)
}).makeToken();

function authenticateClient(userRequestToken) {
  var ref = new Firebase(fb_URL);
  ref.authWithCustomToken(userRequestToken, function (error, authData) {
    if (error) {
      console.log("FB Login Failed!", error);
    } else {
      console.log("FB Login Succeeded!", authData);
    }
  });
  return ref.authData?.auth; // 加个可选链避免未登录时的报错
}

为什么原来的方法不行?

Firebase的自定义令牌要求必须用服务账号的私钥进行RS256非对称签名,而database secret用的是HMAC对称签名。第三方库的createAuthToken方法在传入OAuth access token时,并没有切换到RS256签名模式,还是沿用了HMAC的签名逻辑,导致生成的令牌签名不符合Firebase的验证规则,所以才会出现MAC验证失败的错误。

手动生成JWT的方式严格遵循了Firebase的自定义令牌规范,所以能被客户端正确验证通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:52:06