Firebase Authentication与ADC(应用默认凭据)配合失效问题排查
问题场景
我在开发机器上基于Node.js/Fastify使用Firebase Admin SDK,尝试通过应用默认凭据(ADC)初始化Firebase App,代码如下:
import * as firebaseAdmin from 'firebase-admin' import { applicationDefault } from 'firebase-admin/app' firebaseAdmin.initializeApp({ projectId: '<FIREBASE-PROJECT-ID>', credential: applicationDefault(), }) export default firebaseAdmin
随后使用该实例创建自定义令牌,代码示例:
import firebaseAdmin from '../../../firebase-admin' import { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify' const myRoutes: FastifyPluginAsync<AppOptions> = async (fastify: FastifyInstance) => { fastify.post<{ Body: { uid: string } }>( `/token`, async (request: FastifyRequest<{ Body: { uid: string } }>, reply: FastifyReply) => { const { uid } = request.body try { const customToken = await firebaseAdmin.auth().createCustomToken(uid) return reply.send({ token: customToken }) } catch (error: unknown) { if (error instanceof Error) { app.log.error('Error creating custom token:', { name: error.name, stack: error.stack, message: error.message, }) return reply .code(500) .send({ message: 'Failed to create token', error: error.message }) } else { app.log.error('Unknown error creating custom token:', error) return reply .code(500) .send({ message: 'Failed to create token', error: 'Unknown error' }) } } }, ) }) export default myRoutes
但始终出现如下错误:
无法确定服务账号。请确保使用服务账号凭据初始化SDK,或指定拥有iam.serviceAccounts.signBlob权限的服务账号。原始错误:Error: Error while making request: getaddrinfo ENOTFOUND metadata. 错误代码:ENOTFOUND
我知晓使用服务账号可正常运行(已验证可行),代码如下:
import * as firebaseAdmin from 'firebase-admin' import { applicationDefault } from 'firebase-admin/app' const serviceAccountPath = '/path/to/my/service-account.json' firebaseAdmin.initializeApp({ credential: firebaseAdmin.credential.cert(serviceAccountPath), }) export default firebaseAdmin
但我不想使用服务账号,希望使用gcloud存储在~/.config/gcloud/application_default_credentials.json路径下的ADC(应用默认凭据)。我想了解为何这些凭据无法访问Firebase Auth,该如何使其生效?是否可行?
我已尝试以下操作:
- 安装Firebase CLI,尝试查找类似
~/.config/firebase/application_default_credentials.json的默认凭据文件,打算用其设置GOOGLE_APPLICATION_CREDENTIALS环境变量,但未找到该文件,也不确定其是否存在。 - 为账号授予Firebase Authentication Admin、Editor、Service Account Token Creator等多种权限,但均无效,似乎并非权限问题。
问题原因与解决方案
1. 核心原因:本地环境元数据服务器缺失
当你在本地使用applicationDefault()时,SDK默认会尝试访问GCP元数据服务器获取凭据,但本地开发环境没有这个服务器,所以会抛出getaddrinfo ENOTFOUND metadata错误,这是本地使用ADC的典型问题。
2. 正确配置本地ADC的步骤
要让本地ADC生效,按以下步骤操作:
- 生成有效的应用默认凭据:
打开终端运行gcloud auth application-default login,按照提示完成账号登录。执行完成后,系统会在~/.config/gcloud/application_default_credentials.json生成有效的凭据文件。 - 设置环境变量(可选但推荐):
将GOOGLE_APPLICATION_CREDENTIALS环境变量指向上述文件路径,确保SDK能正确读取:# Linux/macOS export GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/application_default_credentials.json # Windows(PowerShell) $env:GOOGLE_APPLICATION_CREDENTIALS="$HOME\.config\gcloud\application_default_credentials.json" - 初始化代码无需修改:
你原来的初始化代码完全正确,只要上述步骤完成,applicationDefault()会自动读取凭据并正常工作。
3. 权限验证
虽然你已添加权限,但需要确认通过gcloud auth application-default login登录的账号拥有以下关键权限:
iam.serviceAccounts.signBlob:创建自定义令牌必须依赖这个权限,Firebase Auth会调用该接口完成令牌签名。firebase.auth.admin:确保账号具备访问Firebase Auth服务的权限。
如果权限仍有问题,直接给账号添加Service Account Token Creator角色即可,该角色包含iam.serviceAccounts.signBlob权限。
4. 可行性确认
完全可行,本地开发使用ADC是官方推荐的方式,既避免了硬编码服务账号文件的安全风险,也符合GCP/Firebase的凭据管理规范,配置正确后即可正常调用Firebase Auth接口。
内容的提问来源于stack exchange,提问作者rrcabrera9625

