首页 / 资讯中心 / 文章详情

jose JWT 验证实战:jwtVerify 的签名验证与 Claims Set 校验全指南

jose JWT 验证实战:jwtVerify 的签名验证与 Claims Set 校验全指南 ★ FEATURED ARTICLE
网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载导读本指南聚焦 jose 库中 JWTJSON Web Token验证的完整链路jwtVerify函数会先校验 JWT 的 JWS Compact 格式再验证 JWS 签名最后对 JWT Claims Setpayload做严格的声明校验。读完本文你将掌握jwtVerify的三种调用形态直接传密钥 / 传动态 key 解析函数 / 二者兼容的转发重载、JWTVerifyOptions全部选项的语义与底层校验逻辑并能熟练处理JWTExpired、JWTClaimValidationFailed等典型验证失败场景。所有讲解均以本仓库jo/jose的 verify.ts 源码与测试为事实依据。一、jwtVerify 是什么jwtVerify是 jose 中验证「JWS 格式 JWT」的核心函数完整验证过程分三步见 src/jwt/verify.ts格式校验确认 JWT 是合法的 JWS Compact 序列化恰好三段、.分隔签名验证使用提供的密钥或动态解析出的密钥验证 JWS 签名Claims Set 校验按options对 payload 中的iss、sub、aud、exp、nbf、iat等声明做存在性、取值与时间校验。该函数作为命名导出named export同时存在于主入口jose与子路径入口jose/jwt/verify中且本仓库的类型定义文件为 src/types.d.ts。二、函数签名与三种调用形态jwtVerify在 src/jwt/verify.ts 中定义了三个重载形态一直接传入密钥jwtVerifyPayloadType JWTPayload( jwt: string | Uint8Array, key: KeyInput, options?: JWTVerifyOptions, ): PromiseJWTVerifyResultPayloadType形态二传入动态 key 解析函数jwtVerifyPayloadType, KeyType extends CryptoKey | Uint8Array( jwt: string | Uint8Array, getKey: JWTVerifyGetKeyKeyType, options?: JWTVerifyOptions, ): PromiseJWTVerifyResultPayloadType ResolvedKeyKeyType形态三兼容转发重载jwtVerifyPayloadType( jwt: string | Uint8Array, key: KeyInput | JWTVerifyGetKey, options?: JWTVerifyOptions, ): PromiseJWTVerifyResultPayloadType PartialResolvedKey形态三专门用于转发「可能是密钥、也可能是 key 解析函数」的值结果中的key字段仅在使用了解析函数时才会出现源码 src/jwt/verify.ts 通过typeof key function判断后附加key: verified[3]。三种形态都要求密钥满足对应算法的密钥类型要求Algorithm Key Requirements。参数详解参数类型说明jwtstring|Uint8ArrayJSON Web Token 值以 JWS 编码。传入Uint8Array时会被解码为字符串处理keyKeyInput用于验证的密钥。KeyInput定义为CryptoKey \| KeyObject \| JWK \| Uint8Array见 src/types.d.tsgetKeyJWTVerifyGetKey动态解析验证密钥的函数详见第五节options?JWTVerifyOptionsJWS 验证 JWT Claims Set 校验选项详见第六节三、返回结果JWTVerifyResult 与 ResolvedKey验证成功返回PromiseJWTVerifyResultPayloadType定义见 JWTVerifyResult 文档 与 src/types.d.ts字段类型说明payloadPayloadType JWTPayload解析后的 JWT Claims Set可泛型化PayloadType获得类型提示protectedHeaderJWTHeaderParametersJWS Protected Header即 JWT 的受保护头部使用动态 key 解析函数时结果还会附带key字段ResolvedKey其类型由解析函数的返回类型推断见 ResolvedKey 文档。四、四个官方示例从对称密钥到远程 JWKS4.1 对称密钥HS256const secret new TextEncoder().encode( cc7e0d44fd473002f1c42167459001140ec6389b7353f8088f4d9a95f2f596f2, ) const jwt eyJhbGciOiJIUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjY5MDU2MjMxLCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.C4iSlLfAUMBq--wnC6VqD9gEOhwpRZpoRarE0m7KEnI const { payload, protectedHeader } await jose.jwtVerify(jwt, secret, { issuer: urn:example:issuer, audience: urn:example:audience, }) console.log(protectedHeader) console.log(payload)对称密钥场景中密钥就是裸的Uint8Array字节配合 HS256 等 HMAC 算法使用。4.2 公钥 SPKIRS256const alg RS256 const spki -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwhYOFK2Ocbbpb/zVypi9 SeKiNUqKQH0zTKN16fpCTu6ZalGI82s7XK3tan4dJt90ptUPKD2zvxqTzFNfx4H HHsrYCf2FMLn1VTJfQazA2BvJqAwcpW1bqRUEty8tS/Yv4hRvWfQPcc2Gc3/fQ OOW57zVyrNoJc744kb30NjQxdGp03J2S3GLQu7oKtSDDPooQHD38PEMNnITf0pj KgDPjymkMGoJlO3aKppsjfbt/AH6GGdRghYRLOUwQUhofWHR3lbYiKtXPn5dN 24kiHy61e3VAQ9/YAZlwXC/99GGtw/NpghFAuM4P1JDn0DppJldy3PGFC0GfBCZA SwIDAQAB -----END PUBLIC KEY----- const publicKey await jose.importSPKI(spki, alg) const jwt eyJhbGciOiJSUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjY5MDU2NDg4LCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.gXrPZ3yM_60dMXGE69dusbpzYASNA-XIOwsb5D5xYnSxyj6_D6OR_uR_1vqhUm4AxZxcrH1_-XJAve9HCw8az_QzHcN-nETt-v6stCsYrn6Bv1YOc-mSJRZ8ll57KVqLbCIbjKwerNX5r2_Qg2TwmJzQdRs-AQDhy-s_DlJd8ql6wR4n-kDZpar-pwIvz4fFIN0Fj57SXpAbLrV6Eo4Byzl0xFD8qEYEpBwjrMMfxCZXTlAVhAq6KCoGlDTwWuExps342-0UErEtyIqDnDGcrfNWiUsoo8j-29IpKd-w9-C388u-ChCxoHz--H8WmMSZzx3zTXsZ5lXLZ9IKfanDKg const { payload, protectedHeader } await jose.jwtVerify(jwt, publicKey, { issuer: urn:example:issuer, audience: urn:example:audience, }) console.log(protectedHeader) console.log(payload)PEM 格式的公钥需先用importSPKI见 导入文档转换为密钥对象再交给jwtVerify。4.3 公钥 JWKRS256const alg RS256 const jwk { kty: RSA, n: whYOFK2Ocbbpb_zVypi9SeKiNUqKQH0zTKN1-6fpCTu6ZalGI82s7XK3tan4dJt90ptUPKD2zvxqTzFNfx4HHHsrYCf2-FMLn1VTJfQazA2BvJqAwcpW1bqRUEty8tS_Yv4hRvWfQPcc2Gc3-_fQOOW57zVy-rNoJc744kb30NjQxdGp03J2S3GLQu7oKtSDDPooQHD38PEMNnITf0pj-KgDPjymkMGoJlO3aKppsjfbt_AH6GGdRghYRLOUwQU-h-ofWHR3lbYiKtXPn5dN24kiHy61e3VAQ9_YAZlwXC_99GGtw_NpghFAuM4P1JDn0DppJldy3PGFC0GfBCZASw, e: AQAB, } const publicKey await jose.importJWK(jwk, alg) const jwt eyJhbGciOiJSUzI1NiJ9.eyJ1cm46ZXhhbXBsZTpjbGFpbSI6dHJ1ZSwiaWF0IjoxNjY5MDU2NDg4LCJpc3MiOiJ1cm46ZXhhbXBsZTppc3N1ZXIiLCJhdWQiOiJ1cm46ZXhhbXBsZTphdWRpZW5jZSJ9.gXrPZ3yM_60dMXGE69dusbpzYASNA-XIOwsb5D5xYnSxyj6_D6OR_uR_1vqhUm4AxZxcrH1_-XJAve9HCw8az_QzHcN-nETt-v6stCsYrn6Bv1YOc-mSJRZ8ll57KVqLbCIbjKwerNX5r2_Qg2TwmJzQdRs-AQDhy-s_DlJd8ql6wR4n-kDZpar-pwIvz4fFIN0Fj57SXpAbLrV6Eo4Byzl0xFD8qEYEpBwjrMMfxCZXTlAVhAq6KCoGlDTwWuExps342-0UErEtyIqDnDGcrfNWiUsoo8j-29IpKd-w9-C388u-ChCxoHz--H8WmMSZzx3zTXsZ5lXLZ9IKfanDKg const { payload, protectedHeader } await jose.jwtVerify(jwt, publicKey, { issuer: urn:example:issuer, audience: urn:example:audience, }) console.log(protectedHeader) console.log(payload)JWK 明文对象kty/n/e需先经importJWK见 导入文档转为密钥alg参数用于指明后续使用的算法。五、动态密钥解析JWTVerifyGetKey 与远程 JWKS当签名密钥无法预先确定典型场景签发者持有多个密钥、密钥轮换时可传入key 解析函数。接口定义见 JWTVerifyGetKey 文档 与 src/jwt/verify.tsJWTVerifyGetKey(protectedHeader: CompactJWSHeaderParameters, token: FlattenedJWSInput): JWK | KeyObject | KeyType | PromiseJWK | KeyObject | KeyType关键语义调用时机该函数被调用时token 的任何组件都尚未被验证包括签名。因此解析函数内只应基于protectedHeader如alg、kid和token结构选择密钥绝不能假设 token 是可信的失败处理若无法为 token 匹配到合适密钥应主动抛出错误而不是返回空值泛型收窄KeyType泛型默认CryptoKey | Uint8Array决定解析函数返回的密钥类型进而让结果中的ResolvedKey.key在调用侧获得精确推断。createRemoteJWKSet、createLocalJWKSet、EmbeddedJWK这些库内实现都声明只返回CryptoKey因此调用处无需再收窄内置实现createRemoteJWKSet 就是满足该签名的官方解析函数用于验证远程托管的 JSON Web Key Set。远程 JWKS 官方示例const JWKS jose.createRemoteJWKSet(new URL(https://www.googleapis.com/oauth2/v3/certs)) const { payload, protectedHeader } await jose.jwtVerify(jwt, JWKS, { issuer: urn:example:issuer, audience: urn:example:audience, }) console.log(protectedHeader) console.log(payload)注意此形态下结果额外带有key解析出的实际签名密钥可用于后续审计或缓存。六、JWTVerifyOptions全部选项与底层校验逻辑JWTVerifyOptions是「JWS 验证选项」与「JWT Claims Set 校验选项」的组合JWTVerifyOptions extends VerifyOptions, JWTClaimVerificationOptions见 src/jwt/verify.ts完整说明见 JWTVerifyOptions 文档。6.1 算法白名单algorithms类型string[]含义允许的 JWSalgAlgorithm头部参数值列表。默认情况下凡是当前密钥/密钥对象适用的alg均被允许。底层实现在prepareVerify中经validateAlgorithms转为Set见 src/lib/options.ts随后在validateJwsHeaders中检查shared[0].has(alg)不在白名单内直接抛JOSEAlgNotAllowed见 src/lib/jws_verify.ts。安全提醒文档与源码均明确——未受保护的 JWT{ alg: none }永远不会被本 API 接受。6.2 声明校验选项选项类型语义与校验规则issuerstring|string[]期望的iss签发者值。设置后强制要求iss声明必须存在存在但值不匹配时抛JWTClaimValidationFailedaudiencestring|string[]期望的aud受众值。设置后强制要求aud声明必须存在。校验逻辑checkAudiencePresence见 src/lib/jwt_claims_set.tsaud为字符串时要求等于其中某个期望值aud为数组时要求数组包含某个期望值任一匹配即可subjectstring期望的sub主题值设置后强制要求sub存在且严格相等typstring期望的 JWTtypType头部参数值设置后强制要求头部存在该参数。校验采用大小写不敏感归一化normalizeTyp如JWT与application/JWT视为等价见 src/lib/jwt_claims_set.tsmaxTokenAgestring|number允许从iat签发时间算起的最大年龄单位为秒数字或可解析的时间字符串。设置后强制要求iat存在now - iat - tolerance max时抛JWTExpirediat指向未来超过容差时抛JWTClaimValidationFailedclockTolerancestring|number时钟偏差容差秒。用于放宽nbf、exp校验以及设置了maxTokenAge时的iat校验currentDateDate比较 NumericDate 声明时使用的当前时间默认new Date()requiredClaimsstring[]必须存在的声明名数组。默认规则设置了issuer则要求iss、设置了audience则要求aud、设置了subject则要求sub、设置了maxTokenAge则要求iat见 src/types.d.ts6.3 crit关键头部参数处理类型{ [propName: string]: boolean }含义声明对哪些critCritical头部参数「认识」。值为true表示该参数必须受完整性保护false表示无关紧要。内置识别JWS 扩展头部参数b64始终被识别并正确处理其余注册头部参数没有这种内置处理。底层逻辑见 src/lib/options.tscrit中的参数必须在recognized集合内选项与默认集合合并否则抛JOSENotSupported声明为受保护参数却出现在未受保护头部时抛JWSInvalid。重要警告crit选项只校验参数语法正确性与是否受保护它不会替你处理该参数、也不会在参数缺失时拒绝操作——你必须在验证成功后按自己的 profile 校验逻辑自行确认参数存在并处理它。6.4 时间字符串格式与容差解析clockTolerance与maxTokenAge支持人类可读的时间字符串由secs()函数解析见 src/lib/jwt_claims_set.ts。支持的语法大小写不敏感支持空格单位seconds/secs/s、minutes/mins/m、hours/hrs/h、days/d、weeks/w、years/yrs/y数字支持整数与小数如1.5也支持5 seconds、10 minutes、2 hours这类带空格写法可附加ago或from now后缀与正负号互斥如10 minutes ago单位换算系数s1、m60、h3600、d86400、w604800、y31557600非法格式抛TypeError(Invalid time period format)。数字与字符串等价clockTolerance: 5与clockTolerance: 5 seconds效果相同。七、完整校验流程的源码级拆解jwtVerify的实现只有三步核心调用见 src/jwt/verify.tsverifyCompact(jwt, prepareVerify(options), key) ├─ 1. 格式String#split(.) 必须恰好 3 段src/lib/jws_verify.ts 的 verifyCompact ├─ 2. 头部解析 Protected Header校验 alg 存在且在白名单内、处理 crit/b64 ├─ 3. 签名decodeBase64url 取签名按算法 prepareKey 后 verify()失败抛 JWSSignatureVerificationFailed └─ 4. 若 verified[2] 为 false未编码 payload→ 抛 JWTInvalid(JWTs MUST NOT use unencoded payload) validateClaimsSet(verified[1], verified[0], options) // 见 src/lib/jwt_claims_set.ts ├─ payload 必须是顶层 JSON 对象否则 JWTInvalid ├─ 按 presenceCheck 检查 requiredClaims 及由选项推导出的必填声明缺失抛 missing ├─ 匹配 iss / sub / aud 期望值不匹配抛 check_failed ├─ nbfnbf now tolerance → 失败 ├─ expexp now - tolerance → JWTExpired └─ maxTokenAgenow - iat - tolerance max → JWTExpirediat 在未来 → 失败值得注意的是非 base64url 载荷被禁止verified[2]表示载荷是否 base64url 编码JWT 必须使用编码载荷否则抛JWTInvalid载荷声明校验与签名校验解耦只有签名验证通过后才会进入validateClaimsSet保证时序性结果组装始终返回{ payload, protectedHeader }仅当key是函数时才追加key字段。八、错误类型与调试指引所有错误类型集中定义于 src/util/errors.ts对应文档见 errors 文档。jwtVerify涉及的典型错误错误类触发场景判断依据JWSInvalidCompact JWS 不是三段式、头部解析失败、crit/b64语法非法格式问题JOSEAlgNotAllowedalgorithms白名单不包含 token 的alg配置收紧JWSSignatureVerificationFailed签名校验不通过密钥错误或 token 被篡改JWTInvalid载荷不是顶层 JSON 对象、使用了未编码载荷Claims 结构问题JWTClaimValidationFailed必填声明缺失missing、声明值不符check_failed、时间窗校验失败声明不匹配JWTExpiredexp已过、或iat超过maxTokenAge时效性问题JWTClaimValidationFailed携带payload、claim、codemissing/check_failed/invalid等诊断字段便于定位具体声明。测试用例test/jwt/verify.test.ts对上述错误路径均有覆盖例如截断 token 抛JWSInvalid、篡改载荷抛JWSSignatureVerificationFailed、typ不匹配抛JWTClaimValidationFailed等可当作行为规范参考。九、最佳实践小结固定签发者/受众生产环境务必设置issuer与audience可同时杜绝「任意签发者伪造 token」与「token 跨服务复用」收紧算法白名单显式传入algorithms防止算法混淆攻击如把 RS256 换成 HS256密钥轮换用 JWKS多密钥/轮换场景优先createRemoteJWKSet作为getKey并处理其结果中的key字段容忍时钟偏差分布式系统为nbf/exp留出合理的clockTolerance如30s用 maxTokenAge 限制 token 寿命即使exp缺失maxTokenAge也能基于iat强制约束细粒度错误处理按JWTExpired与JWTClaimValidationFailed分别设计过期刷新与参数校验的响应逻辑。以上内容均可在仓库 src/jwt/verify.ts、src/lib/jwt_claims_set.ts、src/lib/jws_verify.ts 与 test/jwt/verify.test.ts 中逐一验证。赞分享网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载相关推荐Kimi Code CLI 插件系统实战用 plugin.json 打造轻量级自定义工具Kimi Code CLI 插件系统实战用 plugin.json 打造轻量级自定义工具 Kimi Code CLI 的插件Plugin系统允许你通过一个网络安全认证鉴权后端抖音批量下载器 douyin-downloader 存储层深度解析SQLite 去重历史、异步文件管理与元数据落盘抖音批量下载器 douyin downloader 存储层深度解析SQLite 去重历史、异步文件管理与元数据落盘 本指南围绕 douyin download网络安全认证鉴权后端Zoom Webhooks 验证指南URL 校验CRC与请求签名验签实战Zoom Webhooks 验证指南URL 校验CRC与请求签名验签实战 导读 本文围绕 Zoom Webhooks 的 身份验证机制 展开完整讲解端点AI 技能AI 插件上一篇Telegraf JOSE 密钥存储插件secretstores.jose完整指南基于 JOSE 加密的文件型密钥管理方案下一篇PostHog AI 可观测性成本拆分指南一份覆盖模型、用户、Trace 与缓存经济学的 SQL 配方集创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站