Fortunately, validating a JWS (and for that matter, a JWE) is very straight-forward thanks to JwtSecurityTokenHandler.ValidateToken().

Quite simply, you take the serialized string, create a TokenValidationParameters object with the relevant fields filled in to validate and then call ValidateToken, it looks like the following. Note that the same code is used for JWS and JWE tokens, the only difference is whether you fill in the TokenDecryptionKey property. This shows both:

 private ClaimsPrincipal ValidateToken(string tokenString, byte[] keybytes)  
{
var signingkey = new X509SecurityKey(new X509Certificate2(certFilePath,certPassword));
var jwt = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(tokenString);
// Verification
var tokenValidationParameters = new TokenValidationParameters()
{
ValidAudiences = new string[]
{
"123456" // Needs to match what was set in aud property of token
},
ValidIssuers = new string[]
{
"https://logindev.pixelpin.co.uk" // Needs to match iss property of token
},
IssuerSigningKey = signingkey,
TokenDecryptionKey = keybytes == null ? null : new SymmetricSecurityKey(keybytes)
};
SecurityToken validatedToken;
var handler = new System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler();
return handler.ValidateToken(tokenString, tokenValidationParameters, out validatedToken);
}

In my method (in a Unit Test), I simply return the ClaimsPrincipal that is returned from ValidateToken() but you could also get the validated and decrypted token that is returned as an out parameter if you wanted to continue to use it.

Also note that I am simply loading the same pfx I used to sign the token to validate it, whereas in real like, you are likely to visit the url of the issuer and perhaps https://theurl.com/.well-known/jwks and find the public key for the signed data using the kid property from the token.

This method allows the caller to pass null for the keybytes if only validating a signed JWS or real key bytes matching the encryption key used for the JWE. This is for pre-shared keys only. In a later post, I will talk about extracting the encryption key, which is actually embedded in a JWE and does not need to be pre-shared.

In part 3, we'll look at JWE (encrypted JWT)