错误信息
jwt malformed
含义
jsonwebtoken 的 jwt.verify() 连令牌都无法解析:这个字符串按点号拆分后不是恰好三段。签名根本没有被检查——你传入的字符串在结构上就不是 JWT。(如果字符串确实有三段,但头部不是 base64url 编码的 JSON,则会在下一步报出“invalid token”。)
原因
Authorization 请求头的拆分方式不对
常见Authorization 请求头的值是“Bearer eyJ...”,而代码保留了错误的那一半:auth.split(" ")[0] 交给 jwt.verify() 的是方案名“Bearer”本身,其中根本没有点号。传入整个“Bearer eyJhbGci...”字符串则会以另一种方式失败——它仍然能拆分成三段,因此当第一段无法解码时,jsonwebtoken 会报出“invalid token”。
传入 verify() 的变量不对
常见本该是令牌的位置收到了一个不是令牌的字符串:对缺失的值做字符串插值得到的“undefined”或“null”(客户端因为什么都没存储而发送“Bearer null”、拼错的 req.headers.authorisation、缺失的 cookie),把解码后的载荷转成字符串、而不是传入原始令牌时得到的“[object Object]”,或者用户 ID。真正的 undefined、null 或空字符串会在更早一步的检查中被拦下,报出的是“jwt must be provided”。
令牌在存储或传输过程中被截断
偶见VARCHAR(255) 类型的数据库列、日志行长度限制,或者丢了末尾部分的复制粘贴,都可能把令牌截断,使剩下的部分不足三段。ES256 令牌约有 200 多个字符;RS256 令牌则要长得多。
它根本不是 JWT
偶见一些 OAuth 提供商签发的是不透明的访问令牌(随机字符串),而不是 JWT。把 Google/GitHub 的不透明 access_token 传给 jwt.verify() 就会在这一步失败——只有 id_token(OpenID Connect)保证是 JWT。
修复方法
- 1.
验证前去掉方案前缀
只取 Authorization 请求头中的令牌部分,并对请求头缺失的情况做好防护,这样失败时返回的是明确的 401,而不是“jwt malformed”。
js const auth = req.headers.authorization ?? ""; const [scheme, token] = auth.split(" "); if (scheme !== "Bearer" || !token) { return res.status(401).json({ error: "missing bearer token" }); } jwt.verify(token, publicKey, { algorithms: ["ES256"] }); - 2.
记录原始值并统计段数
一行日志就能告诉你,问题出在前缀、截断还是变量用错。JWS 恰好有 3 段;JWE 有 5 段;其他情况都不是令牌。
js console.log(JSON.stringify(token).slice(0, 80)); console.log("segments:", String(token).split(".").length); // must be 3 - 3.
检查令牌实际包含的内容
把这个字符串粘贴到下方的 JWT 调试器中:它会在本地解码头部和声明,并准确指出哪一段有问题——或者告诉你这个字符串根本不是 JWT。