Aller au contenu principal

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

  1. Enregistrez le code dans RoktJwtValidator.cs
  2. Créez un nouveau projet .NET : dotnet new console
  3. Installez les dépendances : dotnet add package Microsoft.IdentityModel.Tokens Microsoft.IdentityModel.JsonWebTokens System.IdentityModel.Tokens.Jwt
  4. 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

Cet article vous a-t-il été utile ?