NodeJS 从连接到Google函数的端点调用时,Firebase ID令牌具有不正确的“aud”(受众)声明

2q5ifsrm  于 2022-12-12  发布在  Node.js
关注(0)|答案(3)|浏览(181)

我使用Google Endpoints作为API网关,它运行在Google Run容器服务中。API路径指向Google Function(节点js)。对API网关的调用来自Web应用程序(即浏览器)。
其中一条路径是:/login,它使用firebase.auth().signInWithEmailAndPassword方法在firebase中对用户进行身份验证。我获取用户的令牌ID,并将其在响应报头(身份验证载体)中发送回浏览器。这按预期工作。
当有其他请求(例如/check)发送到端点时,令牌(在头中)会被包含。我想在处理任何请求之前使用Firebase Admin方法检查令牌的有效性。Google函数中为其中一个路由执行此操作的代码如下:

...

const decodeIdToken = async (req, res, next) => {
  // Read the ID Token from the Authorization header.
  const idToken = req.headers.authorization.split('Bearer ')[1];
  try {
    const decodedIdToken = await admin.auth().verifyIdToken(idToken);
    req.decodedToken = decodedIdToken;
    next();
    return;
  } catch (error) {
    return res.status(403).json({
      status: 'failure',
      data: null,
      error: error.message
    });
  }
};

// use decodeIdToken as middleware
app.post('/check', decodeIdToken, (req, res, next) => {
  return res.json({
    status: 'success',
    data: req.decodedToken,
    error: null
  });
});

当我通过直接调用Google Function触发器来调用(通过Postman)路由时,两个路由都有效。但是,当我调用指向Google Function的Google Endpoints时,我在使用Firebase Admin对象时收到以下错误:
Firebase ID令牌具有不正确的\“aud\”(audience)声明。应为\“PROJECT-ID\”,但得到的是\”https://us-central1-PROJECT-ID.cloudfunctions.net/FUNCTION-NAME"。请确保ID令牌与用于验证此SDK的服务帐户来自同一Firebase项目。有关如何检索ID令牌的详细信息,请参见https://firebase.google.com/docs/auth/admin/verify-id-tokens
在NodeJ中设置Firebase Admin对象时,我尝试了以下操作:

const admin = require('firebase-admin');
admin.initializeApp();

以及

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://PROJECT-ID.firebaseio.com"
});
qyswt5oh

qyswt5oh1#

使用X-Apigateway-Api-Userinfo信头

标头的值是JWT的base64编码有效负载。由于API Gateway已经为您验证了标记并使内容可供您使用,因此不需要重新验证。
Node.js开发示例:

Buffer.from(req.header("x-apigateway-api-userinfo"), "base64").toString();

无论出于什么原因,如果您确实需要访问原始JWT,则可以在X-Forwared-Authorization头文件中找到它。
不必要的额外学分:
为了解释这个错误,您得到错误受众声明的原因是因为您尝试验证的JWT是由API Gateway生成的不同JWT。原始授权头被替换为这个JWT。为什么?它告诉云功能“嘿,云功能,是我的API Gateway在呼叫您,这里有一个签名的JWT可以证明这一点”。因此,API Gateway的受众最终是Cloud Function资源URL,而Firebase的受众是的受众是Firebase所在的项目。
如果你问我的话,这只是另一个奇怪的不便的例子,由于谷歌的实现;他们完全可以保留Auth头,让API Gateway使用不同的头,但乞丐不能挑肥拣瘦。🤷‍♂️
Reference API Gateway Documentation
在API中接收经过身份验证的结果
API网关通常会转发它接收到的所有头。但是,当后端地址在API配置中由x-google-backend指定时,它会覆盖原始的授权头。
API网关会将X-Apigateway-Api-Userinfo中的验证结果发送到后端API。建议使用此标头而不是原始授权标头。此标头采用base64 url编码,并包含JWT有效负载。

iibxawm4

iibxawm42#

以下工作不起作用(见下面的注解):
openapi-functions.yaml中添加文档建议的安全定义

securityDefinitions:
    firebase:
      authorizationUrl: ""
      flow: "implicit"
      type: "oauth2"
      # Replace YOUR-PROJECT-ID with your project ID
      x-google-issuer: "https://securetoken.google.com/YOUR-PROJECT-ID"
      x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com"
      x-google-audiences: "YOUR-PROJECT-ID"

然后,针对路径(在我的例子中为/check)添加security部分,如下所示:

/check:
      post:
        ...
        x-google-backend:
           ....
           ....
        security:
           - firebase: []
        ....

请参阅:https://cloud.google.com/endpoints/docs/openapi/authenticating-users-firebase

dwbf0jvd

dwbf0jvd3#

你的admin-sdk设置没有问题,它是idToken,实际上是一个jwt令牌,在使用firebase登录时返回为idToken。
您的问题是您试图使用由auth()函数之一(如firebase.auth().signInWithEmailAndPassword)返回的JWT标记(作为idToken)。这些函数确实返回了JWT标记,但是auth声明可能是错误的,不会通过verifyIdToken的验证。
你必须使用firebase.auth().currentUser.getToken()函数,这个令牌将通过验证。

const idToken=await firebase.auth().currentUser.getToken()

相关问题