You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Node.js的jsonwebtoken库验证Microsoft Entra访问令牌?

解决Microsoft Entra ID访问令牌签名验证失败(invalid signature)问题

以下是针对你遇到的签名验证错误的排查方向和修复方案:

1. 检查JWKS URI是否正确

如果你的应用是单租户,不能使用common端点,必须替换为你的租户ID或租户域名。common是多租户通用端点,若令牌由特定租户颁发,用它获取的密钥可能不匹配。

// 替换为你的租户ID
const TENANT_ID = "your-tenant-id";
const client = jwksClient({
  jwksUri: `https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys`,
});

2. 确认令牌类型是否正确

  • 若你要验证用户身份,前端应传递ID令牌(id_token),而非访问令牌(access_token)。Entra ID的访问令牌默认是加密格式,无法用普通JWT库直接验证。
  • 若必须验证访问令牌,需确保令牌的aud声明是你的API客户端ID,且已在Entra ID中配置允许对该令牌进行签名验证。

3. 补充令牌核心声明验证

必须验证aud(受众)和iss(颁发者),这是令牌有效性的关键,否则即使签名通过,令牌也可能是非法的。修改jwt.verify的配置:

{
  algorithms: options,
  allowInvalidAsymmetricKeyTypes: false,
  audience: "你的API客户端ID", // 替换为你的API客户端ID
  issuer: `https://login.microsoftonline.com/${TENANT_ID}/v2.0`
}

4. 修复密钥获取的错误处理

原代码中getKey函数未传递异步错误,导致密钥获取失败时无法被捕获。修正后:

function getKey(header, callback) {
  client.getSigningKey(header.kid, function (err, key) {
    if (err) {
      return callback(err); // 传递错误给verify方法
    }
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

5. 验证令牌格式完整性

打印前端传递的令牌,确认没有截断、多余空格等格式问题。可先用jwt.decode(token, {complete: true})查看令牌头和负载,检查kid和alg是否与JWKS中的密钥匹配。


修改后的完整代码示例

const bodyParser = require("body-parser");
const express = require("express");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const jwksClient = require("jwks-rsa");
const app = express();

app.use(bodyParser.json());
app.use(cors());

// 替换为你的租户ID和API客户端ID
const TENANT_ID = "your-tenant-id";
const API_CLIENT_ID = "your-api-client-id";

app.post("/v1/teste", (req, res) => {
  const entraAccessToken = req.body.token;
  if (!entraAccessToken) {
    return res.status(400).send("Token missing");
  }

  validaTokenJwks(entraAccessToken, (err, decoded) => {
    if (err) {
      console.log(`TOKEN VALIDATION FAILED: ${err}`);
      return res.status(401).send("Invalid token");
    }
    console.log(`Token validated successfully:`, decoded);
    res.status(200).send("OK");
  });
});

const options = ["RS256"];
const client = jwksClient({
  jwksUri: `https://login.microsoftonline.com/${TENANT_ID}/discovery/v2.0/keys`,
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, function (err, key) {
    if (err) {
      return callback(err);
    }
    var signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

function validaTokenJwks(token, callback) {
  jwt.verify(
    token,
    getKey,
    {
      algorithms: options,
      allowInvalidAsymmetricKeyTypes: false,
      audience: API_CLIENT_ID,
      issuer: `https://login.microsoftonline.com/${TENANT_ID}/v2.0`
    },
    callback
  );
}

app.listen(3000, () => {
  console.log("Server running on port 3000");
});

内容的提问来源于stack exchange,提问作者Pedro Ignacio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:55:25