github.com/go-jose/go-jose/v4(Square の go-jose の後継)は JWS、JWE、JWK、JWT を実装しているため、Go のサービスが暗号化または署名されたトークンをやり取りする場面でよく使われています。4.1.6 は HS、RS、PS、ES の各ファミリーと EdDSA で署名と検証ができました。ES256K、Ed25519、Ed448 はアルゴリズム名として認識されません。
バージョン 4 ではアルゴリズムの一覧が必須になりました。jwt.ParseSigned(token, nil) は no signature algorithms specified で失敗するため、トークンは自分で選んだアルゴリズムに対してしか解析できません。一覧に none があれば署名のないトークンも解析できますが、Claims(key) でそれが検証を通ることは決してありません。読み取る唯一の方法は、検証しないことを名前で明示した UnsafeClaimsWithoutVerification を使うことです。
検証が 2 段階に分かれていることが落とし穴です。token.Claims(key, &claims) は署名を検証して構造体に値を入れます。1 時間前に期限切れになったトークンのクレームも、エラーなしで返しました。有効期限、有効開始時刻(not-before)、発行者、オーディエンスを確認するのは、jwt.Expected の値を渡した claims.Validate() か ValidateWithLeeway だけで、exp のないトークンはそれさえ通過します。サンプルのように、Expiry が設定されていることを確認してください。Validate は jwt.DefaultLeeway(1 分)の誤差を許容し、チェックでもそれを確認しました。
鍵には型があります。PEM のテキストを鍵として作成した HS256 トークンは、*ecdsa.PublicKey に対しては error in cryptographic primitive で失敗しましたが、同じ PEM のバイト列を鍵として渡すと検証を通りました。鍵はバイト列ではなく、解析済みの Go の鍵として保持してください。ES256 は P-384 の鍵を expected 256 bit key, got 384 bits instead で拒否します。DER エンコードの ES256 署名は、偽造された署名と同じ汎用的な error in cryptographic primitive で失敗します。署名の長さは JWT デバッガーで確認できます。
暗号化されたトークンについては、JWE インスペクターでヘッダーとアルゴリズムを確認できます。鍵セットについては、JWKS チェッカーでプロバイダーが公開している内容を確認でき、JWK 変換ツールで鍵を JWK と PEM の間で変換できます。