如何使用JWKS格式公钥验证JWT Token?
问题:将JWKS转换的KeyObject转为JWT验证所需格式
我正在编写一个服务,接收JWT Token并使用JWKS JSON格式的公钥对其进行验证。已成功获取密钥并转换为KeyObject,但不清楚如何将其转换为verifyAsync所需的格式(推测为PEM格式),现有代码如下:
import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { KeyObject, createPublicKey } from 'crypto'; @Injectable() export class TokenValidationService { constructor( private jwtService: JwtService ) { } async validate(token: string): Promise<any | boolean> { const jwt = this.jwtService.decode(token); if (!jwt) { return false; } const jwks: Response = await fetch('https://xxxxxx.auth0.com/.well-known/jwks.json'); const jwksJson = await jwks.json(); const key: KeyObject = createPublicKey({ key: jwksJson.keys[0], format: 'jwk' }) // TODO: Somehow convert this KeyObject into a string that verifyAsync accepts await this.jwtService.verifyAsync(token, { algorithms: ['RS256'], publicKey: myKeyString }) return jwt; } }
解决方案
无需手动将KeyObject转换为PEM字符串,@nestjs/jwt依赖的底层库本身支持直接传入KeyObject作为publicKey参数,直接使用创建好的key变量即可完成验证。同时建议根据JWT头中的kid字段匹配对应密钥(密钥轮换场景下更严谨),修改后的完整代码如下:
import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { KeyObject, createPublicKey } from 'crypto'; @Injectable() export class TokenValidationService { constructor( private jwtService: JwtService ) { } async validate(token: string): Promise<any | boolean> { // 解码完整JWT(包含头信息) const decoded = this.jwtService.decode(token, { complete: true }); if (!decoded) { return false; } // 获取JWKS密钥集 const jwksResponse = await fetch('https://xxxxxx.auth0.com/.well-known/jwks.json'); const jwks = await jwksResponse.json(); // 根据JWT头的kid匹配对应公钥 const matchingKey = jwks.keys.find(key => key.kid === decoded.header.kid); if (!matchingKey) { return false; } // 转换为KeyObject const publicKey: KeyObject = createPublicKey({ key: matchingKey, format: 'jwk' }) // 直接传入KeyObject完成验证 await this.jwtService.verifyAsync(token, { algorithms: ['RS256'], publicKey: publicKey }) return decoded.payload; } }
额外优化建议
- 缓存JWKS:每次验证都请求JWKS接口会降低性能,建议将获取到的密钥集缓存一段时间,定期刷新。
- 错误处理:可以为
fetch和verifyAsync添加异常捕获,返回更明确的验证失败原因。
内容的提问来源于stack exchange,提问作者Mike Christensen
相关产品推荐
相关产品推荐

