github.com/golang-jwt/jwt/v5 は、標準ライブラリの鍵を使って JWT の解析、検証、署名を行います。HMAC には []byte を使い、ほかに *rsa.PublicKey、*ecdsa.PublicKey、ed25519.PublicKey を使います。5.3.1 は HS、RS、PS、ES の各ファミリーと EdDSA で署名と検証ができました。ES256K と、完全指定の Ed25519 と Ed448 という名前には、登録された署名メソッドがありません。
検証の要は、jwt.Parse に渡す keyfunc(鍵を返す関数)です。各署名メソッドは受け取った鍵の Go の型をチェックするため、*ecdsa.PublicKey を返す keyfunc では、RS256 トークンは RSA verify expects *rsa.PublicKey で失敗し、PEM のテキストを鍵とした HS256 トークンは HMAC verify expects []byte で失敗しました。keyfunc がどのトークンに対しても生のバイト列を返すと、この保護はなくなります。チェックでは、PEM ファイルを []byte として読み込む keyfunc を使うと、その偽造された HS256 トークンが検証を通りました。サンプルのように、jwt.WithValidMethods で正確なアルゴリズムを指定し、keyfunc が型付きの鍵を返すようにしてください。
alg: none が検証を通るのは、keyfunc がセンチネル値 jwt.UnsafeAllowNoneSignatureType を返したときだけです。実際の鍵を返すと 'none' signature type is not allowed になります。ES256 は署名時に P-384 の鍵を、詳しい説明のない key is invalid で拒否します。ES256 の署名は JWS が求める 64 バイトの生の r‖s で、DER の署名は crypto/ecdsa: verification error で失敗します。この原因の特定には JWT デバッガーと DER ⇄ 生形式の変換ツールが役立ちます。
v5 ではクレームの検証がデフォルトで有効ですが、exp は任意で(これがないトークンは永久に有効です)、時刻のずれの許容(leeway)もありません。jwt.WithExpirationRequired()、jwt.WithIssuer、jwt.WithAudience、jwt.WithLeeway でこれらの穴をふさげます。エラーは、文字列を比較する代わりに errors.Is(err, jwt.ErrTokenExpired) で判定できます。
ID プロバイダーが発行したトークンを検証するには、JWKS クライアントと組み合わせ、プロバイダーが公開している内容を JWKS チェッカーで確認してください。JWE や JWK の扱いが必要な場合は、go-jose が代わりの選択肢になります。