メインコンテンツまでスキップ

C# JWT 検証例

⚠️ 重要なお知らせ: これはデモンストレーション目的の基本的な例です。実運用で使用する際は、ソフトウェアスタック、セキュリティ要件、デプロイ環境に特化したベストプラクティスを調査し、実装してください。常に組織のセキュリティガイドラインに従い、確立されたJWTライブラリやフレームワークの使用を検討してください。

📝 注記: この例は教育目的でJWKSのダウンロードとファイルキャッシングを示しています。実運用環境では、インフラストラクチャに基づいて、設定管理、環境変数、または好みのキャッシング戦略を使用してJWKSキー管理を実装することを検討してください。

この例では、C#を使用してRokt JWTトークンを検証する方法を示します。

前提条件

必要なNuGetパッケージをインストールします:

<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.0.3" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.0.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />

完全な例

using System;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.JsonWebTokens;
using System.Security.Cryptography;
using System.IdentityModel.Tokens.Jwt;

namespace JwtValidator
{
public class Validator
{
private readonly JwtSecurityTokenHandler _tokenHandler;
private readonly TokenValidationParameters _validationParameters;

public Validator(string publicKeyJwks)
{
_tokenHandler = new JwtSecurityTokenHandler();
_validationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateLifetime = false, // 会社のポリシーを適用
ValidateAudience = true,
ValidateIssuer = true,
ValidIssuer = "Rokt",
ValidAudience = "", // Roktの仕様に従い空の文字列

ClockSkew = TimeSpan.FromMinutes(1) // 本番環境では1分のクロックスキューを許可
};

// JWKSをインポート
ImportFromJwks(publicKeyJwks);
}

public ReferralData ValidateReferralToken(string jwtToken)
{
var result = new ReferralData();

try
{
var principal = _tokenHandler.ValidateToken(jwtToken, _validationParameters, out var validatedToken);

if (principal == null)
{
result.ErrorMessage = "トークンの検証に失敗しました";
return result;
}

result.IsValid = true;

// クレームから紹介データを抽出
if (long.TryParse(principal.FindFirst("cid")?.Value, out long campaignID))
result.CampaignID = campaignID;

if (long.TryParse(principal.FindFirst("crid")?.Value, out long creativeID))
result.CreativeID = creativeID;

// RCLIDを直接処理 - 16進数文字列
string? rclidValue = principal.FindFirst("rclid")?.Value;
if (!string.IsNullOrEmpty(rclidValue))
{
result.RCLID = rclidValue.ToLower();
}

```csharp
// 発行時刻を抽出する
if (validatedToken is JwtSecurityToken jwt)
{
result.IssuedAt = jwt.IssuedAt;
}

return result;
}
catch (Exception ex)
{
result.ErrorMessage = ex.Message;
return result;
}
}

private void ImportFromJwks(string jwksJson)
{
try
{
if (string.IsNullOrEmpty(jwksJson))
throw new ArgumentException("JWKS JSON cannot be null or empty");

var jwks = JsonSerializer.Deserialize<JsonWebKeySet>(jwksJson);
if (jwks?.Keys?.Count > 0)
{
var jwk = jwks.Keys[0];
var parameters = new ECParameters
{
Curve = ECCurve.NamedCurves.nistP256,
Q = new ECPoint
{
X = Base64UrlEncoder.DecodeBytes(jwk.X),
Y = Base64UrlEncoder.DecodeBytes(jwk.Y)
}
};

if (!string.IsNullOrEmpty(jwk.D))
{
parameters.D = Base64UrlEncoder.DecodeBytes(jwk.D);
}

var ecdsa = ECDsa.Create(parameters);
_validationParameters.IssuerSigningKey = new ECDsaSecurityKey(ecdsa);
}
else
{
throw new ArgumentException("No valid keys found in JWKS");
}
}
catch (JsonException ex)
{
throw new ArgumentException($"Invalid JWKS format: {ex.Message}", ex);
}
}

public class ReferralData
{
public long? CampaignID { get; set; }
public long? CreativeID { get; set; }
public string? RCLID { get; set; }
public DateTime? IssuedAt { get; set; }

public bool IsValid { get; set; }
public string? ErrorMessage { get; set; }
}

private static async Task<string> DownloadAndCacheJWKS(string jwksUrl, string cacheFile)
``````csharp
{
// キャッシュファイルが存在し、最近のものであるか(24時間以内)を確認
if (File.Exists(cacheFile))
{
var fileInfo = new FileInfo(cacheFile);
if (DateTime.Now - fileInfo.LastWriteTime < TimeSpan.FromHours(24))
{
Console.WriteLine($"キャッシュされたJWKSを使用: {cacheFile}");
return await File.ReadAllTextAsync(cacheFile);
}
}

// JWKSをダウンロード
Console.WriteLine($"JWKSをダウンロード中: {jwksUrl}");
using var client = new HttpClient();
var response = await client.GetAsync(jwksUrl);
response.EnsureSuccessStatusCode();

var jwksJson = await response.Content.ReadAsStringAsync();

// JWKSをキャッシュ
try
{
await File.WriteAllTextAsync(cacheFile, jwksJson);
Console.WriteLine($"JWKSをキャッシュに保存: {cacheFile}");
}
catch (Exception ex)
{
Console.WriteLine($"警告: JWKSのキャッシュに失敗しました: {ex.Message}");
}

return jwksJson;
}

public static async Task Main(string[] args)
{
// 概要ページからテストトークンをコピー
string sampleToken = "PASTE_TEST_TOKEN_HERE";

// JWKSエンドポイントURL
string jwksUrl = "https://public-api.rokt.com/.well-known/jwks.json";
string jwksCacheFile = "jwks_cache.json";

Console.WriteLine("=== C# JWT バリデーター ===");
Console.WriteLine($"トークン: {sampleToken.Substring(0, Math.Min(50, sampleToken.Length))}...");
Console.WriteLine($"JWKS URL: {jwksUrl}");
Console.WriteLine();

// JWKSをダウンロードしてキャッシュ
string jwksJson = await DownloadAndCacheJWKS(jwksUrl, jwksCacheFile);
Console.WriteLine("JWKSのダウンロードとキャッシュが成功しました");

// JWKSから公開鍵の座標を抽出
var jwks = JsonSerializer.Deserialize<JWKS>(jwksJson);
if (jwks?.Keys == null || jwks.Keys.Length == 0)
{
Console.WriteLine("❌ JWKSにキーが見つかりません");

``````csharp
return;
}

var key = jwks.Keys[0];

var validator = new Validator(jwksJson);
var result = validator.ValidateReferralToken(sampleToken);

if (result.IsValid)
{
Console.WriteLine("✅ トークンの検証に成功しました!");
Console.WriteLine($"キャンペーンID: {result.CampaignID}");
Console.WriteLine($"クリエイティブID: {result.CreativeID}");
Console.WriteLine($"RCLID: {result.RCLID}");
Console.WriteLine($"発行日時: {result.IssuedAt:yyyy-MM-dd HH:mm:ss} UTC");
}
else
{
Console.WriteLine($"❌ トークンの検証に失敗しました: {result.ErrorMessage}");
}
}
}
}

入出力例

入力

  • JWTトークン: Overviewページからテストトークンをコピー
  • 公開鍵ソース: https://public-api.rokt.com/.well-known/jwks.json

出力

=== C# JWT バリデーター ===
トークン: eyJhbGciOiJFUzI1NiIsImtpZCI6InJva3Qtc2lnbmluZy1rZXkiLCJ0eXAiOiJKV1QifQ...
JWKS URL: https://public-api.rokt.com/.well-known/jwks.json

ダウンロード中のJWKS: https://public-api.rokt.com/.well-known/jwks.json
JWKSがキャッシュされました: jwks_cache.json
JWKSが正常にダウンロードおよびキャッシュされました

✅ トークンの検証が成功しました!
キャンペーンID: 3436085368692408324
クリエイティブID: 3437732754935906308
RCLID: 7db958dbd232247a4a8285a34d22fe0f4e9affa463bf5ee54e26721ab0df0e23
発行日時: 2025-08-20 05:10:01 UTC

実行方法

  1. コードを RoktJwtValidator.cs に保存します
  2. 新しい .NET プロジェクトを作成します: dotnet new console
  3. 依存関係をインストールします: dotnet add package Microsoft.IdentityModel.Tokens Microsoft.IdentityModel.JsonWebTokens System.IdentityModel.Tokens.Jwt
  4. 実行します: dotnet run

.csproj を使用した代替実装

.csproj ファイルを作成します:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.0.3" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.0.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
</ItemGroup>
</Project>

ノート

  • 公開鍵はRoktのJWKSエンドポイントから取得されます

  • この例では署名検証にECDSA-256 (ES256)アルゴリズムを使用しています

  • パフォーマンス向上のために公開鍵のキャッシュを検討してください

  • C#はMicrosoft.IdentityModelを通じて優れた暗号化ライブラリを提供しています

この記事は役に立ちましたか?