エラーメッセージ
Invalid Compact JWS
jose (JavaScript) — JWSInvalid, code ERR_JWS_INVALID
このエラーの意味
jose は、入力を JWS コンパクトシリアライゼーションの、ドットで区切られた 3 つのセグメント(header.payload.signature)に分割できませんでした。渡された文字列は構造上、署名付きトークンではありません。暗号処理は一切試みられていません。これは jsonwebtoken の「jwt malformed」に相当する jose のエラーで、それと同じく、問題は JWT ライブラリより前の段階、つまり文字列を生成または伝送した部分にあることを意味します。
発生する理由
トークンが途中で切れている、または別のトークンと連結されている
よくある最後のセグメントが失われた値(データベースのカラム、ログの行、部分的なコピー)や、1 つのヘッダーに連結された 2 つのトークンでは、セグメントがちょうど 3 つではなくなります。欠けのないトークンに「Bearer 」プレフィックスや JSON の引用符が付いているだけでは、このメッセージは出ません。文字列のセグメントは 3 つのままなので、jose は代わりに「JWS Protected Header is invalid」を報告します。末尾の改行は許容されます。
変数にトークンが入っていない
よくある文字列「undefined」に変換された undefined、Cookie がないために生じた空文字列、不透明な(JWT ではない)OAuth アクセストークンは、いずれも JWS の構造を持っていません。失敗の原因は jose より前の段階にあります。
JWS 用の API に JWE を渡している
ときどき暗号化トークン(JWE)のセグメントは 3 つではなく 5 つです。発行者がトークンを暗号化している場合、jwtVerify/compactVerify はここでトークンを拒否します。正しい入口は復号(jwtDecrypt)で、入れ子になった JWS があれば、その後でそれを検証します。
修正方法
- 1.
入力をサニタイズし、セグメント数を確認する
jose を呼び出す前に、前後の空白を除去し、スキームを取り除き、セグメント数をアサートしてください。そうすれば、汎用的な解析エラーではなく、アプリケーション側で正確なエラーを出せます。
js const token = raw.replace(/^Bearer\s+/i, "").trim(); const segments = token.split(".").length; if (segments !== 3) throw new Error(`expected JWS (3 segments), got ${segments}`); - 2.
JWE トークンは復号処理に回す
セグメントが 5 つあれば、そのトークンは暗号化されています。jwtVerify ではなく、受信者の秘密鍵を指定して jwtDecrypt を使ってください。
js import { jwtDecrypt } from "jose"; const { payload } = await jwtDecrypt(token, privateKey); // 5-segment JWE - 3.
文字列がどこで組み立てられたかを追跡する
サニタイズした値でもまだ失敗する場合は、クライアント、ゲートウェイ、ストレージ、ハンドラーといった各経由地点で、値の長さと先頭の数文字をログに記録してください。署名付き JWT の最初のセグメントは base64url でエンコードされた JSON なので、本物のトークンは「eyJ」で始まります('{"' をエンコードした結果です)。これが成り立たなくなった地点で、値が壊れています。
js console.log(token.length, JSON.stringify(token.slice(0, 12))); // healthy: 300+ 'eyJhbGciOiJF'