Node.js验证Azure OAuth JWT令牌遇密钥错误,求排查
解决Azure JWT令牌验证时的
JsonWebTokenError: secret or public key must be provided错误 你的代码存在几个关键问题导致了这个错误,以下是修复方案和问题分析:
问题分析
- 未处理密钥获取失败的情况:当
_client.getSigningKey调用出错,或者返回的key中没有publicKey/rsaPublicKey时,signingKey会是undefined,此时直接调用callback(null, signingKey)会导致jwt.verify无法拿到有效密钥,触发错误。 - 重复创建JWKS客户端实例:每次调用
getSigningKeys都新建一个jwksClient实例,既影响性能,也可能引发不必要的网络请求问题。 - 缺少错误传递逻辑:获取密钥过程中出现的错误没有传递给
jwt.verify的回调,导致验证流程无法感知到密钥获取失败。
修复后的代码
import jwt, { Algorithm, GetPublicKeyOrSecret } from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; import { promisify } from 'util'; // 提前创建JWKS客户端实例,避免重复初始化 const client = jwksClient({ jwksUri: `https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys`, }); const getSigningKeys: GetPublicKeyOrSecret = (header, callback) => { client.getSigningKey(header.kid, (err, key) => { if (err) { // 传递密钥获取错误给验证流程 return callback(err); } const signingKey = key?.publicKey || key?.rsaPublicKey; if (!signingKey) { // 当无法提取有效公钥时,返回明确错误 return callback(new Error('Failed to extract valid public key from JWKS')); } callback(null, signingKey); }); }; export const verifyMicrosoftToken = async (tokenId: string): Promise<any> => { const validationOptions = { audience: CLIENT_ID, issuer: `https://login.microsoftonline.com/${TENANT_ID}/v2.0`, // 标准字段为issuer,jsonwebtoken也兼容iss,但建议用标准字段名 algorithms: ['RS256'] as Algorithm[], }; try { const decodedToken = await promisify(jwt.verify)( tokenId, getSigningKeys, validationOptions ); return decodedToken; } catch (err) { // 可在此统一处理验证错误,比如日志记录 throw err; } };
额外检查项
- 确认
TENANT_ID和CLIENT_ID常量/环境变量已正确配置,值与Azure AD应用注册中的信息完全一致。 - 验证JWT令牌为Azure AD v2.0版本,可通过解码令牌前几位查看
iss字段是否与代码中的issuer值匹配。 - 检查网络是否能正常访问Azure的JWKS端点,避免防火墙或代理阻止请求。
内容的提问来源于stack exchange,提问作者Roberto Rossini
相关产品推荐
相关产品推荐

