JWT.encode と JWT.decode は、Ruby の openssl gem の上で HS、RS、PS、ES の 256/384/512 と ES256K に対応します。EdDSA はもう jwt gem には含まれていません。jwt 3.3.0 だけを読み込んだ状態では EdDSA のエンコードが Unsupported signing method で失敗し、jwt-eddsa を追加すると動作しました。ただし、その依存関係であるネイティブの ed25519 はインストール時に C コンパイラーを必要とし、スリムなコンテナイメージにはコンパイラーが含まれていません。
検証にはアルゴリズムの指定が必須です。algorithm: を付けない JWT.decode(token, key, true) は Expected a different algorithm で失敗しました。署名のないトークンは検証時に拒否され、検証を無効にした場合(JWT.decode(token, nil, false))にしか読めませんが、信頼するトークンに対してコードでこれを行うことは決してすべきではありません。鍵の種類もチェックされます。EC 鍵の PEM テキストで偽造した HS256 トークンは、検証鍵が EC 鍵オブジェクトのときは HMAC key expected to be a String で失敗しました。しかし PEM 文字列を HS256 の鍵として渡すと検証を通ったため、鍵は OpenSSL::PKey オブジェクトのまま扱ってください。ES256 は署名時に P-384 鍵を拒否します。
クレームのチェックはオプトインです。時刻のずれは許容されず、exp は required_claims に列挙しない限り省略可能です。サンプルでは発行者と合わせて列挙しています。HMAC シークレットは長さを問わず受け入れられ、5 バイトの鍵でも警告なしで署名と検証ができたため、シークレットは JWT シークレットチェッカーで確認してください。
ES256 署名は 64 バイトの生の r‖s で、DER 署名は Signature verification failed で失敗します。トークンがどちらのエンコーディングかは、JWT デバッガーに貼り付けると確認できます。