// Verify a CodeB JWT locally in .NET. // Signed with RS256 against the tenant JWKS. European Digital Identity // Wallet id_tokens are validated the same way. // [jwt-validation-cookbook 2026-07-23] // dotnet add package Microsoft.IdentityModel.Protocols.OpenIdConnect // dotnet add package System.IdentityModel.Tokens.Jwt using Microsoft.IdentityModel.Protocols; using Microsoft.IdentityModel.Protocols.OpenIdConnect; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; const string Issuer = "https://"; const string Audience = ""; // ConfigurationManager caches the discovery + JWKS documents (default // 1 day) and auto-refreshes on kid-miss. var mgr = new ConfigurationManager( Issuer + "/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever()); var oidc = await mgr.GetConfigurationAsync(); var handler = new JwtSecurityTokenHandler(); var parms = new TokenValidationParameters { ValidIssuer = Issuer, ValidAudience = Audience, IssuerSigningKeys = oidc.SigningKeys, ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ClockSkew = TimeSpan.FromSeconds(5), }; var principal = handler.ValidateToken(args[0], parms, out _); Console.WriteLine("sub = " + principal.FindFirst("sub")?.Value); Console.WriteLine("role = " + (principal.FindFirst("role")?.Value ?? "user")); // RFCs: 7519 (JWT), 7517 (JWK), 7518 (JWA).