跳到主要内容
ecdsa.com
jose (JavaScript)JWT 库

错误信息

unexpected "iss" claim value

jose (JavaScript) — JWTClaimValidationFailed, code ERR_JWT_CLAIM_VALIDATION_FAILED

含义

令牌通过了密码学验证,但其 `iss` 声明不等于你传给 `jwtVerify` 的 `issuer` 选项。jose 按字符串精确比较(也接受由允许的颁发者组成的数组),因此任何差异——末尾斜杠、不同的租户路径、另一个环境——都会导致检查失败。正是固定颁发者,才能阻止来自另一个身份提供商(或同一提供商的另一个租户)的令牌被接受。

原因

修复方法

  1. 1.

    从发现文档中获取颁发者字符串

    按照规范,`/.well-known/openid-configuration` 中的 `issuer` 值与提供商写入 `iss` 的值完全相同。把它逐字节复制到你的配置中。

    bash
    # The issuer string is defined by the provider's discovery document.
    curl -s https://login.example.com/.well-known/openid-configuration | jq -r .issuer
  2. 2.

    在 jwtVerify 中固定这个确切的值

    保留 `issuer` 选项——没有它,jose 根本不会检查 `iss`——并把它放在同一个常量中,供 JWKS URL 和验证方共用。

    js
    import { createRemoteJWKSet, jwtVerify } from "jose";
    
    const ISSUER = "https://login.example.com/"; // exactly as in "issuer" from discovery
    const jwks = createRemoteJWKSet(new URL("https://login.example.com/.well-known/jwks.json"));
    
    const { payload } = await jwtVerify(token, jwks, { algorithms: ["ES256"], issuer: ISSUER });
  3. 3.

    接受多个颁发者,每个颁发者各用一个密钥集

    如果你的服务确实信任多个颁发者,就根据令牌中(尚未验证的)`iss` 从显式的允许列表中选出密钥集,然后在验证时固定该颁发者。切勿让一个颁发者的密钥验证另一个颁发者的令牌。

    js
    import { createRemoteJWKSet, decodeJwt, jwtVerify } from "jose";
    
    // Each trusted issuer gets its own key set; an unknown iss is rejected before any key is used.
    const trusted = new Map([
      ["https://login.example.com/", createRemoteJWKSet(new URL("https://login.example.com/.well-known/jwks.json"))],
      ["https://partner.example.org", createRemoteJWKSet(new URL("https://partner.example.org/jwks"))],
    ]);
    
    const { iss } = decodeJwt(token);
    const keys = trusted.get(iss);
    if (!keys) throw new Error("untrusted issuer");
    await jwtVerify(token, keys, { algorithms: ["ES256", "RS256"], issuer: iss });

相关错误

浏览完整的签名错误库