2026/9/16 1:29:01

JWT 验签不过?Codex 连上 TaoToken 后能一次查清 Signature 和 exp

JWT 验签不过?Codex 连上 TaoToken 后能一次查清 Signature 和 exp 1. 线上接口突然 401JWT 验签失败的真实现场上周排查一个老项目前端登录正常Token 也拿到了可请求一到服务端就被拦下日志里只有一行Signature verification failed。按经验先看exp发现过期时间设的是 2 小时浏览器端也确认没过期再看Signature代码逻辑和签发时一模一样可服务端就是验不过。这种问题最折磨人——不是不会写 JWT而是写对了却不知道在哪一步被悄悄改掉。后来把验签代码、密钥生成方式、当前时间戳一起丢给 Codex让它按Header、Payload、Signature三段的编码结果逐项比很快定位到问题签发时用的 secret 是旧配置服务端加载的是新配置一长串 HMACSHA256 算出来完全对不上。这里有个可以复用的排查方法也顺带解决 Codex 本身连不上模型服务的问题去 TaoToken 拿一把 Key把 Codex 的 Base URL 指到 TaoToken 的兼容通道同一个会话里既能查 JWT 源码问题又能让 Codex 正常发起模型请求完成后续调试。2. 先把 JWT 的 Signature 和 exp 拆开看JWT 由三段用点号拼接的文本组成每一段都有明确职责。Header声明令牌类型和签名算法常见写法是{alg:HS256,typ:JWT}Payload放用户身份和标准声明比如sub、iat、expSignature则是对前两段做签名防止内容被篡改。很多人验签失败问题往往不在算法本身而是对 Signature 的生成过程理解不够精确。以 HS256 为例签名公式是这样HMACSHA256( base64UrlEncode(header) . base64UrlEncode(payload), secret )这里有几个容易忽略的细节。第一Base64Url 编码和标准 Base64 不一样要换成-/要换成_末尾的要删掉第二签名输入是header.payload这个带点号的字符串不是分别对两段签名再拼接第三secret 参与的是原始字符串不是 Base64 之后的版本。任何一处不一致服务端验签必挂。exp的问题同样隐蔽。很多团队直接用System.currentTimeMillis()得到毫秒值塞进 Payload而 JWT 标准要求的是秒还有人用本地时间带时区偏移服务端用 UTC 比于是明明刚签发的 Token 也报过期。这两类错误在日志里都表现为 401但成因完全不同排查路径也不一样。3. 用 Codex 排查 401 前先让 Codex 能跑起来排查这类问题最自然的方式是把 Token、密钥、验签代码一起交给 Codex让它按步骤对着算。但前提是 Codex 得先能正常发起模型请求这就绕不开 API 通道。打开 TaoToken 注册并创建 API Key然后把 Codex 指到兼容通道过程只需要改一个配置文件。这里要分清两个地址官网落地页只用来注册、创建 Key、看模型广场和用量填进 Codex 的 Base URL是接口地址末尾不要加/v1。很多工具默认在 Base URL 后面补/v1如果你填了带/v1的路径反而会拼成/v1/v1导致 404。打开~/.codex/config.toml按下面的方式配置model 你的模型ID [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api api_key_env_var TAOTOKEN_API_KEY配置解释配置项值说明base_urlhttps://taotoken.net/api兼容通道接口末尾不加/v1api_key_env_varTAOTOKEN_API_KEY从环境变量读取 Key避免写死在配置里model以模型广场当时列表为准不要凭记忆填版本号随后把 Key 放进环境变量不同终端写法略有差异# bash / zsh export TAOTOKEN_API_KEYYOUR_API_KEY # Windows PowerShell $env:TAOTOKEN_API_KEYYOUR_API_KEY这里的YOUR_API_KEY是占位符需要到 TaoToken 控制台创建。环境变量设置好以后重启 Codex 再试一次对话如果仍然报 401请回看这段配置检查base_url是否被追加了/v1以及环境变量名是否和配置文件里的api_key_env_var完全一致。4. 让 Codex 按 signature、exp、jti 逐项查通道就绪后把问题描述得越具体Codex 给出的结论越接近真相。我习惯按下面这个模板把信息一次性交给它我在做一个 JWT 登录接口现在请求返回 401错误信息是 Signature verification failed。 请帮我按以下顺序排查 1. 检查 Signature已知 Header 是 xxxPayload 是 xxxsecret 是 xxx 请用 HMACSHA256 重新计算签名并与 Token 第三段逐字符比对 2. 检查 exp当前 Unix 时间戳是 xxxToken 里 exp 的值是 xxx 请确认单位是秒还是毫秒以及是否存在时区问题 3. 检查 jti这个字段是否被服务端用于防重放是否误把已使用的 jti 当作重复请求。 以下是完整代码和完整 Token [粘贴代码] [粘贴Token]Codex 拿到之后会真的把 Header 和 Payload 解出来重新编码再算一遍 Signature 给你看。上次排查时它发现我的 Header 里写的算法是HS256但服务端代码实际操作的是HS512密钥长度也不合规范这两处叠加导致每次签名都不同。这个结论光靠肉眼盯代码很难发现因为两边变量名都是secret很容易默认它们值相同。jti是 Payload 里的唯一标识标准里用于防止重放攻击。有些实现会把jti存到 Redis 并设置过期时间但如果你在本地测试时把 Redis 里的记录清掉了同一个 Token 再次携带jti过来会被判定为已使用同样返回 401。Codex 能帮你从代码里找出这一层逻辑避免你在 Signature 上反复折腾。还有一个常见的坑是密钥格式。有人把 secret 直接写在代码里有人放在环境变量里有人从配置中心拉取。只要有一处带引号、一处没有引号算出来的签名就是两套结果。检查时可以要求 Codex 在代码里搜索secret的全部赋值点列出所有不同值这一步通常能直接命中问题。5. 验证 Token 是否有效的三种快捷方式改完代码后建议先不急着发起完整请求用最小化手段确认 JWT 本身是否合法。下面三个方法可以独立使用也可以互相印证。5.1 用 Codex 生成一段验签脚本把下面这个 Node.js 脚本交给 Codex 补全运行逻辑它可以独立于业务代码完成验签const crypto require(crypto); function base64url(input) { return Buffer.from(input) .toString(base64) .replace(//g, ) .replace(/\/g, -) .replace(/\//g, _); } function verifySignature(token, secret) { const [header, payload, signature] token.split(.); const data ${header}.${payload}; const expected crypto .createHmac(sha256, secret) .update(data) .digest(base64) .replace(//g, ) .replace(/\/g, -) .replace(/\//g, _); return expected signature; } // 请 Codex 根据你的算法HS256/HS512调整 createHmac 参数 // 并补上 exp 过期判断这段脚本的重点在于它完全复刻了 JWT 签名的标准化流程。如果脚本里验签通过但服务端验签失败问题一定出在服务端加载的 secret 或者算法选择上如果脚本里就验不过直接对比 Header 和 Payload 的 Base64Url 编码结果看看是不是哪一位字符被替换错了。5.2 在 TaoToken 模型对话里做交叉验证如果你的时间戳换算总是不放心可以在 TaoToken 模型对话 里直接问当前 Unix 时间戳是多少同时把你计算出的exp值贴进去让模型帮你做一次单位换算。这样能得到一个独立于你本地环境的回答尤其适合排查时区问题。5.3 回控制台确认这次调用已计账Codex 发起请求会消耗 Token 额度。验证完 JWT 之后打开 TaoToken 控制台 API Keys 看一眼 Key 的调用记录如果看到了刚才那次请求说明 Base URL 和 Key 都配置正确问题确实在 JWT 验签逻辑本身。6. 把签证失败的根因转成可落地的修复清单排查结束后不要让结论停留在“签名不对”这个层面要把根因拆成可执行的修正项。以最常见的几类问题为例根因现象修复动作签发与验签 secret 不一致每次验签都失败但日志无异常统一从同一环境变量读取密钥exp 用了毫秒值Token 刚发出来就报过期改为Math.floor(Date.now() / 1000)Base64Url 编码不规范偶尔成功偶尔失败统一用工具函数处理不手动拼接算法声明与实际不一致Header 写 HS256 实际用 HS512两边统一使用同一常量修复时建议一次只改一项改完立刻用上面的 Node 脚本重验。Codex 可以在你修改后继续扮演代码审查者帮你检查是否引入了新问题比如把exp修正成秒之后iat是否也相应调整了单位。密钥管理这一块强烈建议写入项目的环境变量模板文件并备注格式要求JWT_SECRET请填写与签发时完全一致的密钥 JWT_EXPIRE_SECONDS3600服务端读取时统一走配置中心业务代码里不要出现任何硬编码密钥。只要这种规范建立起来后面再有人碰到验签失败可以先自查密钥来源不用每次从头查一遍。7. 顺路把后续接口调试也跑通Token 验签通过只代表身份认证这一关过了后面的业务接口可能还会继续抛参数错误、权限不足等问题。此时 Codex 已经连着 TaoToken 的通道你可以继续把接口返回的 JSON、报文头、甚至数据库查询语句丢给它做对照分析不用再切换任何配置。如果你接下来要高频使用 Codex 写代码、查接口可以考虑先看一下 Coding Plan 的套餐是否更划算如果只是偶尔调试直接按量走就够。创建新 Key 可以随时到 TaoToken 控制台 操作旧 Key 需要吊销时也在同一个页面处理。整个过程走下来最值钱的不是某一行修复代码而是建立了一套排查路径先确认通道可用再把问题拆成 Signature、exp、jti 三个独立检查点最后用脚本验证。下次再遇到 401你不需要从零开始。