#:package Microsoft.IdentityModel.JsonWebTokens@8.23.0using Microsoft.IdentityModel.JsonWebTokens;using Microsoft.IdentityModel.Tokens; // Fetch the issuer's key set once (cache it; refetch on a schedule or on an unknown kid)using var http = new HttpClient();var jwks = new JsonWebKeySet(await http.GetStringAsync("https://issuer.example.com/.well-known/jwks.json")); var parameters = new TokenValidationParameters{ ValidIssuer = "https://issuer.example.com", ValidAudience = "api://orders", IssuerSigningKeys = jwks.GetSigningKeys(), // the handler picks the one whose kid matches ValidAlgorithms = ["ES256"], // never let the token choose the algorithm RequireExpirationTime = true,};var handler = new JsonWebTokenHandler(); foreach (var line in File.ReadLines("tokens.txt")){ if (line.Split(' ') is not [var label, var token]) continue; TokenValidationResult result = await handler.ValidateTokenAsync(token, parameters); // returns, does not throw Console.WriteLine(result.IsValid ? $"{label}: accepted, sub={result.Claims["sub"]}" : $"{label}: rejected: {result.Exception.GetType().Name}: {result.Exception.Message.Split('.')[0]}"); // "IDXnnnnn: …"}How it works
new JsonWebKeySet(json)parses the JWKS;GetSigningKeys()turns each usable JWK into aSecurityKeywith itsKeyId.TokenValidationParameterslists what a valid token is:ValidIssuer,ValidAudience,IssuerSigningKeys,ValidAlgorithmsandRequireExpirationTime.ValidateTokenAsyncreturns aTokenValidationResultinstead of throwing;IsValid,ClaimsandExceptiondescribe the outcome.- The IDX codes identify the check that failed: IDX10214 audience, IDX10205 issuer, IDX10223 lifetime, IDX10503 no key for the
kid.
Gotchas
- In ASP.NET Core, prefer
AddJwtBearerwithoptions.Authority: it reads the issuer's discovery document, fetches the JWKS and refreshes it on rotation. Loading the JWKS by hand, as here, suits workers and tests, and then refreshing is your job. - Leaving
ValidAudienceunset does not skip the check, it fails (IDX10208: Unable to validate audience).ValidateAudience = falseturns it off — and makes tokens for other APIs valid for yours. - Exception messages hide values as
[PII of type … is hidden]unlessIdentityModelEventSource.ShowPIIis on; enable it only in development. ValidAlgorithmsis not set by default. Set it, so the accepted algorithm is part of your configuration rather than whatever the keys happen to support.