First create two RSA keys:
RSA rsa1 = RSA.Create(2048);
RSA rsa2 = RSA.Create(2048);
RsaSecurityKey publicKey1 = new(rsa1.ExportParameters(false))
{
KeyId = "keyId1"
};
RsaSecurityKey publicKey2 = new(rsa2.ExportParameters(false))
{
KeyId = "keyId2"
};
RsaSecurityKey publicAndPrivateKey1 = new(rsa1.ExportParameters(true))
{
KeyId = "keyId1"
};
RsaSecurityKey publicAndPrivateKey2 = new(rsa2.ExportParameters(true))
{
KeyId = "keyId2"
};
Use them to create two JWK's:
JsonWebKey jwk1 = JsonWebKeyConverter.ConvertFromRSASecurityKey(publicKey1);
JsonWebKey jwk2 = JsonWebKeyConverter.ConvertFromRSASecurityKey(publicKey2);
Add them to a JWKS and print it using JsonExtensions.SerializeToJson() method (which works better than Newtonsoft JSON here, because the output can be passed back to the JsonWebKey and JsonWebKeySet constructors):
IList<JsonWebKey> jwksList = new List<JsonWebKey>
{
jwk1,
jwk2,
};
Dictionary<string, IList<JsonWebKey>> jwksDict = new()
{
{ "keys", jwksList }
};
string jwksStr = SerializeToJson(jwksDict);
Console.WriteLine(jwksStr); // put this at https://example.com/.well-known/jwks.json
JsonWebKeySet jwks = new(jwksStr);
Then issue two JWT's:
JsonWebTokenHandler tokenHandler = new();
SecurityTokenDescriptor descriptor1 = new()
{
Issuer = "example.com",
Audience = "cats",
SigningCredentials = new SigningCredentials(publicAndPrivateKey1, SecurityAlgorithms.RsaSsaPssSha256),
};
SecurityTokenDescriptor descriptor2 = new()
{
Issuer = "example.com",
Audience = "dogs",
SigningCredentials = new SigningCredentials(publicAndPrivateKey2, SecurityAlgorithms.RsaSsaPssSha256),
};
string jwt1 = tokenHandler.CreateToken(descriptor1);
string jwt2 = tokenHandler.CreateToken(descriptor2);
Finally, validate the two tokens if someone gives them back to you:
TokenValidationParameters parameters = new()
{
ValidateIssuer = true,
ValidIssuer = "example.com",
ValidateAudience = true,
ValidAudiences = new[] { "cats", "mice" }, // "dogs" are not allowed
IssuerSigningKeys = jwks.GetSigningKeys(),
};
TokenValidationResult result1 = tokenHandler.ValidateToken(jwt1, parameters);
TokenValidationResult result2 = tokenHandler.ValidateToken(jwt2, parameters);
Console.WriteLine("jwt1 is valid: " + result1.IsValid);
Console.WriteLine("jwt2 is valid: " + result2.IsValid);
Screenshot of my console app:

Here the Nuget packages used in the .csproj file:
<ItemGroup>
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.25.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.0" />
</ItemGroup>
and the using
statements:
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
using static System.IdentityModel.Tokens.Jwt.JsonExtensions;