JJWT 0.12 以降は、メソッドチェーンで書くビルダーとパーサー(Jwts.builder()…signWith(key, alg) と Jwts.parser().verifyWith(key)…parseSignedClaims(token))を提供し、アルゴリズムは Jwts.SIG にまとめられています。配布は 3 つのアーティファクトに分かれており、コンパイル時には jjwt-api、実行時には jjwt-impl と、jjwt-jackson などの JSON バインディングを使います。0.13.0 は 256/384/512 の HS、RS、PS、ES と EdDSA で署名と検証ができました。ES256K と、Ed25519、Ed448 という名前は Jwts.SIG にありません。
パーサーは検証鍵から許可するアルゴリズムを導き、エラーメッセージもそれをはっきり示します。EC 公開鍵に対する RS256 トークンと、EC 鍵の PEM テキストを鍵とした HS256 トークンは、どちらも、その鍵はそのアルゴリズムには使えないと説明する UnsupportedJwtException で失敗しました。保護しているのはアルゴリズムの一覧ではなく鍵の型です。Keys.hmacShaKeyFor(pemBytes) を渡したパーサーはその偽造トークンの検証を通したため、公開されうるデータから HMAC 鍵を作ってはいけません。
署名のないトークンは、parseSignedClaims が RFC 7518 §3.6 を引用するメッセージで拒否し、読み取れるのは Jwts.parser().unsecured()…parseUnsecuredClaims を通した場合だけです。弱い HMAC 鍵はそもそもそこまで到達しません。RFC 7518 はハッシュ以上の長さの鍵を求めているため、Keys.hmacShaKeyFor は 16 バイトの鍵を WeakKeyException で拒否しました。ES256 は署名時に P-384 の鍵を拒否します。
注意が必要なデフォルトが 2 つあります。時刻のずれは許容されず(3 秒前に期限切れになったトークンは失敗しました)、exp も任意です。サンプルのように clockSkewSeconds を設定し、有効期限と発行者をチェックしてください。ES256 の署名は 64 バイトの生の r‖s で、DER の署名は正確に報告されます(Provided signature is 576 bits (72 bytes) but ES256 signatures must be exactly 512 bits (64 bytes))。JJWT は、エンコーディングの問題を名指しする数少ないライブラリの 1 つです。トークンは JWT デバッガーで、HMAC 鍵は JWT シークレットチェッカーで確認してください。
JWE や JWK セットを大規模に扱う場合は、Nimbus JOSE + JWT と比較してください。