Exemple de validation JWT en C#
⚠️ Avis Important : Ceci est un exemple basique à des fins de démonstration uniquement. Pour une utilisation en production, veuillez rechercher et mettre en œuvre les meilleures pratiques spécifiques à votre pile logicielle, vos exigences de sécurité et votre environnement de déploiement. Suivez toujours les directives de sécurité de votre organisation et envisagez d'utiliser des bibliothèques et frameworks JWT établis.
📝 Remarque : Cet exemple démontre le téléchargement de JWKS et la mise en cache de fichiers à des fins éducatives. Dans les environnements de production, vous pouvez choisir de mettre en œuvre la gestion des clés JWKS différemment en fonction de votre infrastructure - comme en utilisant la gestion de configuration, les variables d'environnement ou votre stratégie de mise en cache préférée.
Cet exemple montre comment valider les jetons JWT de Rokt en utilisant C#.
Prérequis
Installez les packages NuGet requis :
<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" />
Exemple Complet
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, // appliquez la politique de votre entreprise
ValidateAudience = true,
ValidateIssuer = true,
ValidIssuer = "Rokt",
ValidAudience = "", // Chaîne vide selon la spécification Rokt
ClockSkew = TimeSpan.FromMinutes(1) // Autoriser un décalage d'horloge d'une minute pour la production
};
// Importer 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 = "Échec de la validation du jeton";
return result;
}
result.IsValid = true;
// Extraire les données de parrainage des revendications
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;
// Gérer RCLID - chaîne hexadécimale directement
string? rclidValue = principal.FindFirst("rclid")?.Value;
if (!string.IsNullOrEmpty(rclidValue))
{
result.RCLID = rclidValue.ToLower();
}
```csharp
// Extraire le temps d'émission
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
{
// Vérifier si le fichier de cache existe et est récent (moins de 24 heures)
if (File.Exists(cacheFile))
{
var fileInfo = new FileInfo(cacheFile);
if (DateTime.Now - fileInfo.LastWriteTime < TimeSpan.FromHours(24))
{
Console.WriteLine($"Utilisation du JWKS mis en cache depuis : {cacheFile}");
return await File.ReadAllTextAsync(cacheFile);
}
}
// Télécharger le JWKS
Console.WriteLine($"Téléchargement du JWKS depuis : {jwksUrl}");
using var client = new HttpClient();
var response = await client.GetAsync(jwksUrl);
response.EnsureSuccessStatusCode();
var jwksJson = await response.Content.ReadAsStringAsync();
// Mettre en cache le JWKS
try
{
await File.WriteAllTextAsync(cacheFile, jwksJson);
Console.WriteLine($"JWKS mis en cache dans : {cacheFile}");
}
catch (Exception ex)
{
Console.WriteLine($"Avertissement : échec de la mise en cache du JWKS : {ex.Message}");
}
return jwksJson;
}
public static async Task Main(string[] args)
{
// Copier le jeton de test depuis la page d'aperçu
string sampleToken = "PASTE_TEST_TOKEN_HERE";
// URL du point de terminaison JWKS
string jwksUrl = "https://public-api.rokt.com/.well-known/jwks.json";
string jwksCacheFile = "jwks_cache.json";
Console.WriteLine("=== Validateur JWT en C# ===");
Console.WriteLine($"Jeton : {sampleToken.Substring(0, Math.Min(50, sampleToken.Length))}...");
Console.WriteLine($"URL JWKS : {jwksUrl}");
Console.WriteLine();
// Télécharger et mettre en cache le JWKS
string jwksJson = await DownloadAndCacheJWKS(jwksUrl, jwksCacheFile);
Console.WriteLine("JWKS téléchargé et mis en cache avec succès");
// Extraire les coordonnées de la clé publique du JWKS
var jwks = JsonSerializer.Deserialize<JWKS>(jwksJson);
if (jwks?.Keys == null || jwks.Keys.Length == 0)
{
Console.WriteLine("❌ Aucune clé trouvée dans le JWKS");
``` return;
}
var key = jwks.Keys[0];
var validator = new Validator(jwksJson);
var result = validator.ValidateReferralToken(sampleToken);
if (result.IsValid)
{
Console.WriteLine("✅ Validation du jeton réussie !");
Console.WriteLine($"ID de la campagne : {result.CampaignID}");
Console.WriteLine($"ID créatif : {result.CreativeID}");
Console.WriteLine($"RCLID : {result.RCLID}");
Console.WriteLine($"Émis à : {result.IssuedAt:yyyy-MM-dd HH:mm:ss} UTC");
}
else
{
Console.WriteLine($"❌ Échec de la validation du jeton : {result.ErrorMessage}");
}
}
}
}
Exemple d'entrée/sortie
Entrée
- Jeton JWT : Copiez le jeton de test depuis la page d'aperçu
- Source de la clé publique :
https://public-api.rokt.com/.well-known/jwks.json
Sortie
=== Validateur JWT C# ===
Token: eyJhbGciOiJFUzI1NiIsImtpZCI6InJva3Qtc2lnbmluZy1rZXkiLCJ0eXAiOiJKV1QifQ...
URL JWKS : https://public-api.rokt.com/.well-known/jwks.json
Téléchargement de JWKS depuis : https://public-api.rokt.com/.well-known/jwks.json
JWKS mis en cache dans : jwks_cache.json
JWKS téléchargé et mis en cache avec succès
✅ Validation du token réussie !
ID de la campagne : 3436085368692408324
ID de la création : 3437732754935906308
RCLID : 7db958dbd232247a4a8285a34d22fe0f4e9affa463bf5ee54e26721ab0df0e23
Émis à : 2025-08-20 05:10:01 UTC
Comment exécuter
- Enregistrez le code dans
RoktJwtValidator.cs - Créez un nouveau projet .NET :
dotnet new console - Installez les dépendances :
dotnet add package Microsoft.IdentityModel.Tokens Microsoft.IdentityModel.JsonWebTokens System.IdentityModel.Tokens.Jwt - Exécutez :
dotnet run
Implémentation alternative avec .csproj
Créez un fichier .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>
Notes
-
La clé publique est récupérée à partir du point de terminaison JWKS de Rokt
-
L'exemple utilise l'algorithme ECDSA-256 (ES256) pour la vérification de signature
-
Envisagez de mettre en cache la clé publique pour améliorer les performances
-
C# offre d'excellentes bibliothèques cryptographiques via Microsoft.IdentityModel