JWT 调试指南:exp 过期、签名失败、Base64 解不开
JWT 调试的三个高频问题:过期时间、签名校验失败、Base64URL 解不开。本文讲清各报错的真实含义与排查顺序,以及在浏览器本地安全查看令牌内容的方法。
先看清 JWT 的结构
一个 JWT 是三段用 . 分隔的 Base64URL 文本:头部.载荷.签名。前两段是 Base64URL 编码的 JSON,可以直接解出来读;签名段是服务端用密钥算出来的校验值,客户端改不了也解不开。
所以调试 JWT 时,第一步永远是先解前两段看内容,很多时候问题在解码阶段就能定位。
问题一:exp 提示过期
exp(expiration time)是过期时间戳,单位是秒,不是毫秒。常见误判:
- 把秒当毫秒比较——当前时间要写成
Date.now()/1000才是秒。 - 本机时钟偏差——服务器时间不准也会导致误判过期,检查 NTP 同步。
- 真的过期——令牌有效期通常配置为 15 分钟到 24 小时,需要刷新机制。
问题二:signature 校验失败
签名算法和密钥不匹配,或令牌内容被改动过。排查顺序:
- 先确认头部声明的算法(
alg)与服务端一致。历史上有「算法混淆」攻击:把alg改成none或HS256冒充RS256,服务端若未固定校验算法就会误信任。 - 确认载荷没被改动。载荷虽然可见,但任何一位改动都会让签名对不上。
- 用相同算法和密钥重新计算签名做对比——DevKit 的 HMAC 签名工具可以直接验证 HS256 场景。
注意:HS256 用对称密钥(同一个密钥签名和验证),RS256 用私钥签名、公钥验证,两者的密钥不是一回事。
问题三:Base64 解不开
几乎都是变体用错。JWT 用的是 Base64URL:+→-、/→_、去掉末尾 =。用标准 Base64 解就会失败或得到乱码。DevKit 的 JWT 解析工具会自动处理这个差异。
安全提醒
JWT 的载荷是签名而非加密,任何拿到令牌的人都能解出里面的内容。所以不要在载荷里放密码、身份证号等敏感信息。需要保密应改用 JWE 或直接传输加密数据。
本地调试时可以直接把令牌粘进 DevKit 的 JWT 解析工具——它在浏览器内完成计算,令牌不会上传服务器,适合排查生产环境的真实令牌。
常见问题
- JWT 可以解码吗?
- 前两段(头部、载荷)用 Base64URL 编码,可以直接解码查看内容。签名段是用密钥计算的校验值,无法解码还原。
- JWT 载荷能放敏感信息吗?
- 不建议。载荷只是编码不是加密,任何拿到令牌的人都能解出内容。敏感信息应放服务端,前端只保留必要的标识类字段。
- exp 用毫秒还是秒?
- 用秒。JWT 规范中 exp 是 NumericDate,单位为秒。如果你的系统里存的是毫秒时间戳,比较前需要除以 1000。