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

C# JWT Validation Example

⚠️ Important Notice: This is a basic example for demonstration purposes only. For production use, please research and implement best practices specific to your software stack, security requirements, and deployment environment. Always follow your organization's security guidelines and consider using established JWT libraries and frameworks.

📝 Note: This example demonstrates JWKS downloading and file caching for educational purposes. In production environments, you may choose to implement JWKS key management differently based on your infrastructure - such as using configuration management, environment variables, or your preferred caching strategy.

This example demonstrates how to validate Rokt JWT tokens using C#.

Prerequisites

Install the required NuGet packages:

<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" />

Complete Example

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, // Disable expiration check for demo - using sample token
ValidateAudience = false,
ValidateIssuer = false
};

// 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 1 hour old)
if (File.Exists(cacheFile))
{
var fileInfo = new FileInfo(cacheFile);
if (DateTime.Now - fileInfo.LastWriteTime < TimeSpan.FromHours(1))
{
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}");
}
}
}
}

Input/Output Example

Input

  • JWT Token: Copy the test token from the Overview page
  • Public Key Source: https://public-api.rokt.com/.well-known/jwks.json

Output

=== 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

How to Run

  1. Save the code to RoktJwtValidator.cs
  2. Create a new .NET project: dotnet new console
  3. Install dependencies: dotnet add package Microsoft.IdentityModel.Tokens Microsoft.IdentityModel.JsonWebTokens System.IdentityModel.Tokens.Jwt
  4. Run: dotnet run

Alternative Implementation with .csproj

Create a .csproj file:

<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>

Notes

  • The public key is retrieved from Rokt's JWKS endpoint

  • The example uses ECDSA-256 (ES256) algorithm for signature verification

  • Consider caching the public key for performance

  • C# provides excellent cryptographic libraries through Microsoft.IdentityModel

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