示例说明
对称 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);