← 中文资源

简体中文版本

Jose ES256 非对称 JWT 签发与验证

用 jose 库基于 ECDSA P-256 密钥对签发 JWT,验证时显式核对签发方、受众与过期时间并容忍小时钟偏差。

阅读英文原文

示例说明

对称 HMAC 签名要求验证方与签发方共享同一密钥,微服务场景下密钥分发风险高。ES256 非对称签名只有签发方持有私钥,公钥可以放心分发给任何需要验证的服务。jose 基于 WebCrypto 标准 API,在 Node、浏览器、边缘运行时行为一致。

技术要点

  • generateKeyPair 生成 ECDSA P-256 密钥对
  • setProtectedHeader 显式声明算法防降级攻击
  • 验证时锁定 issuer 与 audience 双方声明

代码解读

签发链先创建密钥对,再用链式调用填充受保护头与注册声明,15 分钟过期适合访问令牌。jwtVerify 传入公钥并给出期望的 issuer 与 audience,任一不匹配即抛错;clockTolerance 吸收多机部署的秒级时钟偏差。protectedHeader 返回实际使用的算法,可再次断言防算法混淆。

使用建议

私钥必须存放在密钥管理系统而非代码仓库,定期轮换并把公钥以 JWKS 端点暴露。access token 保持短时效,长会话交给 refresh token。clockTolerance 不超过 60 秒,过大窗口会削弱过期保护。

代码示例

import { SignJWT, jwtVerify, generateKeyPair, ExportJWK } from 'jose';

const { publicKey, privateKey } = await generateKeyPair('ES256', {
  extractable: true,
});

const secretClaims = { sub: 'user-42', role: 'editor' };

const token = await new SignJWT(secretClaims)
  .setProtectedHeader({ alg: 'ES256', typ: 'JWT' })
  .setIssuer('https://auth.example.com')
  .setAudience('api://orders')
  .setExpirationTime('15m')
  .setIssuedAt()
  .sign(privateKey);

const { payload, protectedHeader } = await jwtVerify(token, publicKey, {
  issuer: 'https://auth.example.com',
  audience: 'api://orders',
  clockTolerance: 5,
});

console.log(protectedHeader.alg, payload.role, payload.exp);