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

使用jose库签名JWT后无法加密完整签名JWT的技术求助

解决jose库先签名再加密JWT的问题

错误原因

控制台报错TypeError: JWT Claims Set MUST be an object,是因为你把签名后的JWT字符串直接传给了EncryptJWT的payload参数,但EncryptJWT要求传入的是JSON对象类型的Claims集合,而非已签名的JWT字符串。

解决方案

要实现先签名再加密的流程,需将已签名的JWT作为嵌套内容包装成一个对象,再传给EncryptJWT处理。具体步骤如下:

1. 调整调用逻辑,先签名再包装加密

先调用你的签名函数得到已签名的JWT字符串,再将其封装为对象传入加密函数:

// 1. 生成签名后的JWT
const originalPayload = { userId: 123, username: "test" };
const signedJwt = await _encrypt(originalPayload);

// 2. 将签名JWT包装成对象,传入加密函数
const encryptedJwt = await encrypt({
  payload: { nestedJwt: signedJwt },
  maxAge: 3600 // 加密后的有效期,按需调整
});

2. (可选)优化加密函数参数类型

如果想让加密函数更明确支持嵌套JWT的场景,可以修改参数定义:

async function encrypt({
  nestedJwt,
  maxAge,
}: {
  nestedJwt: string;
  maxAge: number;
}): Promise<string> {
  const secret: Uint8Array = randomBytes(32);
  const salt = randomBytes(16);
  const encryptionSecret: Uint8Array = await hkdf(
    "sha256",
    secret,
    salt,
    "Generated Encryption Key",
    32
  );
  
  // 直接把已签名JWT包装为对象作为加密payload
  return new EncryptJWT({ nestedJwt })
    .setProtectedHeader({ alg, enc })
    .setIssuedAt()
    .setExpirationTime(now() + maxAge)
    .setJti(crypto.randomUUID())
    .encrypt(encryptionSecret);
}

3. 解密与验证流程

拿到加密后的JWT后,需要先解密取出嵌套的签名JWT,再验证签名:

// 解密加密后的JWT
const decryptedResult = await jwtDecrypt(encryptedJwt, encryptionSecret);
// 取出嵌套的签名JWT
const nestedSignedJwt = decryptedResult.payload.nestedJwt;
// 验证签名并获取原始payload
const verifiedResult = await jwtVerify(nestedSignedJwt, key);
console.log("原始payload:", verifiedResult.payload);

注意事项

  • 加密所用的encryptionSecret和salt在实际场景中需妥善存储,否则无法解密;示例中临时生成的方式仅用于演示。
  • 签名和加密的算法可根据需求调整,但需确保jose库支持对应算法组合。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:12:21