C# による JWT の生成と検証

ここでは JSON Web Token (JWT) を C# で利用する方法について説明します。

C# で利用できる JWT ライブラリ

C# で JWT (JSON Web Token) を利用するためのライブラリとして人気があるのが、その名の通りの JWT パッケージです。 Nuget を利用することで簡単に C# プロジェクトに取り込むことができます。

2019年12月現在、最新安定バージョンは 5.3.1 です。5.3.1 は .NET Framework 4.6 以降、.NET Standard 1.3 以降で利用可能です。

JWT 5.3.1 を Visual Studio プロジェクトにインストールするには、次のコマンドでインストールします。

> Install-Package JWT -Version 5.3.1

バージョン 6 以降で Newtonsoft の JSON ライブラリの依存関係がなくなる予定ですが、バージョン 6 は現在まだベータ版です。このため 5.3.1 を使うことにします。

尚、C# で JWT を使うためのライブラリはマクロソフトの System.IdentityModel.Tokens.Jwt をはじめ、 jose-jwtjose-rt など各種あります。

私が試した限り、この JWT ライブラリが最も直感的に使いやすく機能的にも十分と思います。

C# による JWT の生成方法

実際に JWT ライブラリを使って、トークンを生成してみましょう。

ここではトークンの有効期限を現在から 3 時間とします。

トークンの追加情報 (JWT ではクレーム (claim) といいます) としてユーザーを識別するため、メールアドレスを設定します。 さらにもうひとつ、任意のクレームとして data1 というのを設定しています。

using JWT.Algorithms;
using JWT.Builder;
using System;

namespace TestApp {

  class Program {

    const string secret = "secret_goes_here";

    static void Main(string[] args) {

      var jwtToken = new JwtBuilder()
        .WithAlgorithm(new HMACSHA256Algorithm())
        .WithSecret(secret)
        .AddClaim("exp", DateTimeOffset.UtcNow.AddHours(3).ToUnixTimeSeconds())
        .AddClaim("email", "foo@example.com")
        .AddClaim("data1", "hello!")
        .Build();

      Console.WriteLine(jwtToken);
    }
  }
}

これを実行すると次のように出力されます。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1NzU2MzU0MjcsImVtYWlsIjoiZm9vQGV4YW1wbGUuY29tIiwiZGF0YTEiOiJoZWxsbyEifQ.J5OZHjyGBYfIW0NHV2JzKynU9vmdMstfXQFUFYqVj44

これが JWT トークンです。

典型的な使い方としては、ウェブの JavaScript クライアントアプリケーションで、認証時にトークンを受け取り localStorage に保存しておきます。 その後、サーバー側のバックエンドに接続が必要な場合、Authorization ヘッダにこのトークンをセットして HTTP(S) 要求を送ります。

この文字列が正しいトークンとして出来上がっているかどうか、どうすれば確認できるでしょうか。

C# による JWT の検証方法

JWT Debugger による検証方法

次のサイトに JWT Debugger というページがあります。

jwt.io

ここにトークンを貼り付けます。これでヘッダーとペイロードが入力済みになります。

そして、右側下側の VERIFY SIGNATURE (署名の検証) の中のシークレット (上の例では secret_goes_here という文字列) を入力します。

この結果、サイト上で出来上がったトークン (文字列) と一致すれば意図したトークンが生成できていると言って良いです。

JWT プログラムでの検証方法

JWT ライブラリを使って、トークンの検証を行う方法を説明します。

また、ここではトークンのペイロード部分を MyToken というクラスのオブジェクトとして作成します。

上で JWT を作成したので、引き続き作成した JWT を検証してみましょう。

using JWT;
using JWT.Algorithms;
using JWT.Builder;
using Newtonsoft.Json;
using System;
using System.Threading;

namespace TestApp {

  class MyToken {
    public long exp { get; set; }
    public string email { get; set; }
    public string data1 { get; set; }
  }

  class Program {

    const string secret = "secret_goes_here";

    static void Main(string[] args) {
      // JWT の生成
      var jwtToken = new JwtBuilder()
        .WithAlgorithm(new HMACSHA256Algorithm())
        .WithSecret(secret)
        .AddClaim("exp", DateTimeOffset.UtcNow.AddHours(3).ToUnixTimeSeconds())
        .AddClaim("email", "foo@example.com")
        .AddClaim("data1", "hello!")
        .Build();

      Console.WriteLine(jwtToken);

      // 検証
      try {

        var json = new JwtBuilder()
          .WithSecret(secret)
          .MustVerifySignature()
          .Decode(jwtToken);

        Console.WriteLine(json);

        // JSON から MyToken オブジェクトへのデシリアライズ
        var token = JsonConvert.DeserializeObject<MyToken>(json);

        Console.WriteLine($"exp:   {token.exp}");
        Console.WriteLine($"email: {token.email}");
        Console.WriteLine($"data1: {token.data1}");

      }
      catch (TokenExpiredException) {
        Console.Error.WriteLine("The token has expired.");
      }
      catch (SignatureVerificationException) {
        Console.WriteLine("Invalid signature.");
      }
      catch (Exception ex) {
        Console.WriteLine($"{ex.Source}: {ex.Message}");
      }
    }
  }
}

上のコードで検証が成功すると変数 json に、トークンのペイロード部分を表す JSON 文字列が返ります。

もし検証中に問題が検出されたときには、例外が発生して処理が中断します。

例えば、検証時点でトークンの有効期限が切れている場合TokenExpiredException 例外が発生します。

また、署名が正しくない場合 SignatureVerificationException 例外が発生します。

例外が発生しない時は、検証が成功したということです。つまり、改竄されていない、有効期限内のトークンであるということが確認できたということです。

  var json = new JwtBuilder()
    .WithSecret(secret)
    .MustVerifySignature()
    .Decode(jwtToken);

  Console.WriteLine(json);

  // JSON から MyToken オブジェクトへのデシリアライズ
  var token = JsonConvert.DeserializeObject<MyToken>(json);

上述のように、この部分で変数 json には、トークン内のペイロード部分の JSON 文字列がセットされます。

C# で JSON 文字列をそのまま読み取るのは面倒なので、JsonConvert クラスの DeserializeObject メソッドで MyToken というクラスのオブジェクトに変換しています。

これによって、メールアドレスフィールドの値や、data1 フィールドにも簡単にアクセスできるようになります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 C# 入門