🤔

【JWT】デコード時に発生したエラー Unable to decode the payload の解決方法

2024/04/20に公開

Microsoft.AspNetCore.Authentication.JwtBearer Version=7.0.14より後のバージョンから、Iat(発行日時)は数値のみを受け取るようになりました。
https://github.com/dotnet/aspnetcore/issues/5219
トークンを生成すること自体はできるが、デコードしようとするとUnable to decode the payload '[PII of type 'System.String' is hiddenのエラーが発生します。
対応策として、Iatを文字列ではなく数値としてクレームに追加してトークンを生成します。

DateTime nowDateTime = DateTime.now;
var clams = new []{
new Claim(JwtRegisteredClaimNames.Iat, EpochTime.GetIntDate(nowDateTime).ToString(CultureInfo.InvariantCulture),ClamValueTypes.Integer64)
...(省略)
}

EpochTime.GetIntDateは、指定された日時(今回はnowDateTime)をUNIX時間に変換し、
ToString(CultureInfo.InvariantCulture)を使用して文字列へと変換しています。
ToStringの引数CultureInfo.InvariantCultureは、特定の言語、地域に依存することなく変換するために指定しています。
CultureInfo.InvariantCultureを指定しなかった場合、日付を文字列化するにあたって地域によって違いがあります。
日本では「年/月/日(yyyy/mm/dd)」の形式ですがアメリカでは「月/日/年(mm/dd/yyyy)」の形式が一般的です。
異なる地域でも一貫した値を得るためにCultureInfo.InvariantCultureを指定します。

DateTime nowDateTime = DateTime.Now;

string formattedDateUS = nowDateTime.ToString(new CultureInfo("en-US"));
string formattedDateJP = nowDateTime.ToString(new CultureInfo("ja-JP"));
string formattedDateCommon = nowDateTime.ToString(CultureInfo.InvariantCulture);

Console.WriteLine(formattedDateUS);
-> 4/19/2024 11:52:26 PM
Console.WriteLine(formattedDateJP);
-> 2024/04/19 23:52:26
Console.WriteLine(formattedDateCommon);
-> 04/19/2024 23:52:26

最初にも記載した通りIatは数値にしなければなりません。
そのためClamValueTypes.Integer64で64ビットの整数であることを示しています。
64ビットにしたのは、UNIX時間を表現するために十分な幅をもっているためです。

以上によって、生成したトークンをエラーなくデコードできます!

Discussion