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

C# JWT Validation Example

⚠️ 重要なお知らせ: これはデモンストレーション目的の基本的な例です。本番環境で使用する場合は、ソフトウェアスタック、セキュリティ要件、デプロイ環境に特化したベストプラクティスを調査し、実装してください。常に組織のセキュリティガイドラインに従い、確立された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, // apply your company policy
ValidateAudience = true,
ValidateIssuer = true,
ValidIssuer = "Rokt",
ValidAudience = "", // Empty string as per Rokt specification

ClockSkew = TimeSpan.FromMinutes(1) // Allow 1 minute clock skew for production
};

// Import 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 = "Token validation failed";
return result;
}

result.IsValid = true;

// Extract referral data from claims
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;

// Handle RCLID - hex string directly
string? rclidValue = principal.FindFirst("rclid")?.Value;
if (!string.IsNullOrEmpty(rclidValue))
{
result.RCLID = rclidValue.ToLower();
}

// Extract issued at time
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)
{
// Check if cache file exists and is recent (less than 24 hours old)
if (File.Exists(cacheFile))
{
var fileInfo = new FileInfo(cacheFile);
if (DateTime.Now - fileInfo.LastWriteTime < TimeSpan.FromHours(24))
{
Console.WriteLine($"Using cached JWKS from: {cacheFile}");
return await File.ReadAllTextAsync(cacheFile);
}
}

// Download JWKS
Console.WriteLine($"Downloading JWKS from: {jwksUrl}");
using var client = new HttpClient();
var response = await client.GetAsync(jwksUrl);
response.EnsureSuccessStatusCode();

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

// Cache the JWKS
try
{
await File.WriteAllTextAsync(cacheFile, jwksJson);
Console.WriteLine($"JWKS cached to: {cacheFile}");
}
catch (Exception ex)
{
Console.WriteLine($"Warning: failed to cache JWKS: {ex.Message}");
}

return jwksJson;
}

public static async Task Main(string[] args)
{
// Copy the test token from the Overview page
string sampleToken = "PASTE_TEST_TOKEN_HERE";

// JWKS endpoint URL
string jwksUrl = "https://public-api.rokt.com/.well-known/jwks.json";
string jwksCacheFile = "jwks_cache.json";

Console.WriteLine("=== C# JWT Validator ===");
Console.WriteLine($"Token: {sampleToken.Substring(0, Math.Min(50, sampleToken.Length))}...");
Console.WriteLine($"JWKS URL: {jwksUrl}");
Console.WriteLine();

// Download and cache JWKS
string jwksJson = await DownloadAndCacheJWKS(jwksUrl, jwksCacheFile);
Console.WriteLine("JWKS downloaded and cached successfully");

// Extract public key coordinates from JWKS
var jwks = JsonSerializer.Deserialize<JWKS>(jwksJson);
if (jwks?.Keys == null || jwks.Keys.Length == 0)
{
Console.WriteLine("❌ No keys found in JWKS");
return;
}

var key = jwks.Keys[0];

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

if (result.IsValid)
{
Console.WriteLine("✅ Token validation successful!");
Console.WriteLine($"Campaign ID: {result.CampaignID}");
Console.WriteLine($"Creative ID: {result.CreativeID}");
Console.WriteLine($"RCLID: {result.RCLID}");
Console.WriteLine($"Issued At: {result.IssuedAt:yyyy-MM-dd HH:mm:ss} UTC");
}
else
{
Console.WriteLine($"❌ Token validation failed: {result.ErrorMessage}");
}
}
}
}

入出力例入出力例 への直接リンク

入力入力 への直接リンク

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

出力出力 への直接リンク

=== C# JWT Validator ===
Token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJva3Qtc2lnbmluZy1rZXkiLCJ0eXAiOiJKV1QifQ...
JWKS URL: https://public-api.rokt.com/.well-known/jwks.json

Downloading JWKS from: https://public-api.rokt.com/.well-known/jwks.json
JWKS cached to: jwks_cache.json
JWKS downloaded and cached successfully

✅ Token validation successful!
Campaign ID: 3436085368692408324
Creative ID: 3437732754935906308
RCLID: 7db958dbd232247a4a8285a34d22fe0f4e9affa463bf5ee54e26721ab0df0e23
Issued At: 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を使用した代替実装 への直接リンク

.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を通じて優れた暗号化ライブラリを提供します

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