Firebase Auth ID 令牌的“aud”声明不正确
Posted
技术标签:
【中文标题】Firebase Auth ID 令牌的“aud”声明不正确【英文标题】:Firebase Auth ID token has incorrect "aud" claim 【发布时间】:2016-11-15 01:32:36 【问题描述】:我正在尝试验证 idToken 后端。用户已成功登录到 Firebase 客户端,但是当我尝试在后端验证 idToken 时,我收到这个不是很有帮助的错误消息
错误消息似乎变得更加有用,归结为在 auth 键中没有项目名称:
错误:Firebase ID 令牌的“aud”(受众)声明不正确。 预期“stripmall-0000”但得到 “617699194096-0aafcvsml0gke61d6077kark051f3e1.apps.googleusercontent.com”。 确保 ID 令牌与 用于验证此 SDK 的服务帐户。看 https://firebase.google.com/docs/auth/server/verify-id-tokens 为 有关如何检索 ID 令牌的详细信息。
任何人都知道可能出了什么问题?我从客户端正确收到了 tokenId,所以这应该不是问题。如果以前有人问过这个问题或以任何其他方式微不足道,请真诚地道歉。
firebase.initializeApp(
serviceAccount:
"type": "service_account",
"project_id": <project id here>,
"private_key_id": <key id goes here>,
"private_key": <key goes here>
"client_email": <email goes here>,
"client_id": <my client id>,
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": <url goes here>
,
databaseURL: <my db url here>
);
router.post("/verify", function (req, res)
firebase.auth().verifyIdToken(req.body.idToken).then(function (decodedToken)
var uid = decodedToken.sub;
res.send(uid);
).catch(function (error, param2)
console.log(error); // 'Firebase Auth ID token has incorrect "aud" claim'
);
);
【问题讨论】:
据我了解,aud
用于“受众”,在这种情况下指的是项目 ID。你确定那里有正确的 project_id 吗?
嗯,它们是直接从你下载的 json 文件传递过来的,所以无法想象那个会有什么问题..
我也看到这一直是错误的。它会得到进一步的信息,我的受众密钥应该是什么。
【参考方案1】:
您的问题可能是您尝试使用 auth()
函数之一返回的 JWT 令牌,例如 firebaseRef.auth().signInWithPopup()
。这些确实返回了一个 JWT 令牌,但是身份验证声明可能是错误的,并且不会通过 verifyIdToken
的验证。 Firebase 技术支持证实了这一点。
您必须使用firebaseRef.auth().currentUser.getToken()
函数。该令牌将通过验证。
【讨论】:
对我有用,这应该被接受为正确答案 我确认这个工作,我在2018年才遇到这个问题。使用user.getIdToken()
解决问题。
他们的技术支持是否解释了为什么会这样?
对于遇到此问题的任何人,实际上正确使用的是 firebase.auth().currentUser.getIdToken()
如果来自firebase.auth().onIdTokenChanged(async (user) => if (user) const token = await user.getIdToken();
的令牌不起作用,我应该如何使用firebase.auth().currentUser.getToken()
进行服务器端身份验证,例如NextJS?【参考方案2】:
TLDR:正如另一个答案中提到的,您没有正确初始化应用程序。
虽然我在这方面有点晚了,但我也遇到了同样的问题,所以我决定深入了解背后发生了什么。
首先,除非在提出此问题后 API 已更改,否则 serviceAccount
不作为属性作为 AppOptions
接口的一部分存在,这可能就是您收到错误的原因。因此,我将假设您所拥有的内容应包含在 credential
键中。
其次,您会看到在 https://github.com/firebase/firebase-admin-node/blob/master/src/auth/token-verifier.ts(撰写本文时的第 187 行)引发了此错误,其中将令牌中的 aud
声明与 this.projectId
进行比较。
现在,正如其他答案所提到的,这可能是因为您尝试验证的令牌不是在客户端创建的,而是通过其他一些自定义方法创建的,在这种情况下,aud
声明可能不存在,完全随机的东西,或者绝对不等于你的projectId
,所以你应该先检查一下。
但是,如果您确定令牌是在客户端创建的,则归结为 projectId
未设置,或者至少未按您期望的方式设置。如果您查看https://github.com/firebase/firebase-admin-node/blob/master/src/utils/index.ts 中的getProjectId()
方法(撰写本文时的第66 行),您会看到projectId
是通过以下三种方式之一确定的:直接来自app.options
对象,来自@ app.options.credential
中的 987654334@ 属性,或来自 process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT
。这意味着如果未设置 projectId
并且您的项目托管在 GCloud 上(我假设 stripmall-0000
是),那么 Google 将自动将您当前环境的 projectId 用于与 firebase-auth 相关的任何内容,而不是原始项目的 projectId。
所以,三个选项:
使用直接在AppOptions
中设置的projectId
初始化您的应用:
firebase.initializeApp(
databaseURL: <my db url here>,
// Set your projectId directly here in options:
projectId: <your-projectId-here>
);
或者通过正确设置您的凭据对象可能更好地做到这一点:
firebase.initializeApp(
credentials: admin.credential.cert(<<path-to-your-certificate> || <admin.ServiceAccount object>>),
databaseURL: <my db url here>
);
或者,只需将应用程序托管在与您的 Firebase 应用程序相同的项目中(现在它们是同一生态系统的一部分),以便环境变量相同。 (实际上并不是 100% 关于这一点,但我假设这就是 firebase-functions a.k.a. cloud-functions 的工作原理)
【讨论】:
这解决了我的问题。我正在使用一个服务帐户来操作来自不同项目的多个 Firebase。如果不明确传递 projectId,它只会尝试写入创建服务帐户的项目。【参考方案3】:我的问题是不是令牌,而是我需要使用服务帐户初始化我的后端。这样做您还可以从本地开发服务器进行测试和调试。
FileInputStream serviceAccount = new FileInputStream("path/to/serviceAccountKey.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
// Get the FB uid from the token
FirebaseToken decodedToken = firebaseAuth.verifyIdTokenAsync(token).get();
String uid = decodedToken.getUid();
来源:https://firebase.google.com/docs/admin/setup
【讨论】:
【参考方案4】:正如 Thach Lockevn 在 cmets 中提到的 对我有用的解决方案是:
import AngularFireAuth from '@angular/fire/auth';
import auth from 'firebase/app';
this.angularFireAuth.signInWithPopup(new auth.GoogleAuthProvider()).then((googleAuth) =>
this.user = googleAuth.user;
googleAuth.user.getIdToken().then(tkn =>
this.token = tkn;
//send the token to the backend...
);
);
【讨论】:
【参考方案5】:如果您在本地运行,如果您的 GOOGLE_APPLICATION_CREDENTIALS 环境变量不正确,也会弹出此错误消息。检查此环境变量设置的 JSON 键是否与项目的匹配。
【讨论】:
【参考方案6】:还有另一种情况会产生这种令人沮丧的错误。如果您打开了 Postman、Insomnia、GraphQL Playground(这次是罪魁祸首)等查询工具,那么即使您的身份验证密钥已更改,这些工具也可能持有旧的身份验证承载令牌并向您的 API 发出请求。
这里的简单解决方案是清除当前使用这些 Bearer 令牌进行身份验证的所有请求并重新进行身份验证。
这对于 GraphQL Playground 来说尤其令人讨厌,因为它的基本特性迫使您将身份验证令牌复制/粘贴到每个查询选项卡的标题中,因此如果您不关闭或修改每个选项卡,您仍然会正在向您的 API 控制台发送此错误消息。
我推荐 Insomnia 作为解决此问题的方法,与正确的查询链接做法一样,您可以完全避免这种情况。更多详细信息:您可以通过 Insomnia 的环境变量之一将用户身份验证查询的不记名令牌结果自动传递给任何其他查询。
【讨论】:
【参考方案7】:错误的受众(错误的项目 GOOGLE 项目之间的冲突 FIX)
我在 GKE 集群中使用 NetJS 服务器(使用帐户 A 创建),并尝试将管理 SDK 连接到外部 Firebase 应用(使用帐户 B 创建)。
GKE 使用影响 NextJS 应用的环境变量设置凭据
解决方案
我为 NextJS 应用设置了GOOGLE_APPLICATION_CREDENTIALS
环境(您可以使用.env
文件。
结论
Node 变量优先于默认的 auth 应用程序(疯狂!)
https://firebase.google.com/docs/admin/setup#initialize_the_sdk
【讨论】:
【参考方案8】:auth ID Token有两种
-
基于谷歌
Firebase 提供 AuthIDToken
如果您使用 Firebase 身份验证实现它,则需要 Firebase 提供的 Token。
您将获得第一个 Google id 令牌,并使用该令牌获得用于身份验证 firebase 的凭据 ,这里提供
idToken : 谷歌 id 令牌
AuthCredential credential = GoogleAuthProvider.getCredential(idToken, null)
您正在使用
登录firebasefirebase.signInWithCredential(credential).addOnCompleteListener(this, task -> ....)
在此回调中,您将获得 firebase id 令牌
ftoken : firebase id 令牌
String ftoken = task.getResult().getUser().getIdToken(false).getResult().getToken()
【讨论】:
以上是关于Firebase Auth ID 令牌的“aud”声明不正确的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET 核心策略检查中缺少“aud”声明会阻止授权,但它位于 id 令牌中
如何从 Firebase.auth.currentUser Android Kotlin 获取刷新令牌
如何使用 Firebase Auth 将令牌发送回 android