如何在Node.js中使用jose验证Firebase会话Cookie(JWT)
需求背景
我目前使用Firebase的verifySessionCookie方法验证会话Cookie,代码能正常工作:
export async function getDecodedSessionCookie() { // 获取sessionCookie const sessionCookie = cookies().get("sessionCookie") if (sessionCookie === undefined) return null // 验证Cookie但不检查是否已撤销,不确定这是否有安全风险,但这样会增加显著延迟 return ( adminAuth .verifySessionCookie(sessionCookie.value, false) // 验证通过则返回解码后的Claims .then((decodedClaims) => { return decodedClaims }) .catch((e) => console.log("error", e)) ) }
但这个方法速度极慢,而且无法在Vercel Edge Runtime中执行。我打算参考官方文档和Python示例,使用jose包(也可接受其他Node.js包)来验证JWT格式的会话Cookie。
已尝试方案
我对这个主题了解有限,以下是我的尝试代码:
export async function getDecodedSessionCookie2() { // 如果Cookie不存在或无效则返回null const sessionCookie = cookies().get("sessionCookie") if (sessionCookie === undefined) return null // 解码头部(这一步能正常工作) const header = jose.decodeProtectedHeader(sessionCookie.value) console.log("header", header) // 解码Cookie(这一步能正常工作) const sessionCookieDecoded = jose.decodeJwt(sessionCookie.value) console.log("sessionCookieDecoded", sessionCookieDecoded) // 创建远程密钥集(此处报错:JSON Web Key Set malformed) const JWKS = jose.createRemoteJWKSet( new URL( "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com" ) ) const keyset = await JWKS() console.log("keyset", keyset) // 后续代码从未执行到这里 const audience = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID const issuer = `https://securetoken.google.com/${audience}` // 后续代码从未执行到这里 const { payload, protectedHeader } = await jose.jwtVerify( sessionCookie.value, JWKS, { issuer, audience, } ) console.log("protectedHeader", protectedHeader) console.log("payload", payload) // 不确定这一步是否需要? // const x509 = certificates["7cf7f8727091e4c77aa995db60743b7dd2bb70b5"] // const ecPublicKey = await jose.importX509(x509, algorithm) return sessionCookieDecoded }
我认为需要用createRemoteJWKSet创建远程密钥集,但这一步始终报错,导致后续验证无法进行。
补充说明
- Firebase令牌的头部应包含
kid字段:- 生产环境中我看到
kid: lk02Aw,但这个值和公开密钥不匹配; - 使用Auth Emulator本地开发时,
kid字段不存在。
- 生产环境中我看到
- 想了解公开证书是否会频繁变更?
更新记录
- 借助jose包作者的指导,我已经解决了上述错误,完成令牌验证后会更新完整细节。
- 我了解到Google公开密钥每12小时轮换一次。
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

