Search code examples
jwtasp.net-core-mvc.net-5asp.net-core-5.0

Verifying a JWT encrypted token with ASP.NET Core 5


After scavenging bits and pieces from the net and trying to make it work, I gave up.

So here it is:

I have an OpenID token with a signature encryption of RSA-SHA256. I've tried the following code using JWT.net library

This is the token:

eyJhbGciOiJSUzI1NiIsImtpZCI6Ii11Zm0wSEVuMVpSbktHV2ZmQUttd0h0bEV4RSJ9.eyJzdWIiOiJhbG9uIiwiYXVkIjoiMTIzNDUiLCJqdGkiOiJMeVlDeGo4MzNEbHV3V2h0Q0s4OXZmIiwiaXNzIjoiaHR0cHM6Ly8xMC4xNDYuMzIuMTY0OjkwMzEiLCJpYXQiOjE2NDUwMjU4NjYsImV4cCI6MTY0NTAyNjE2NiwiYXV0aF90aW1lIjoxNjQ1MDI1ODY2fQ.KtS1WR3A61uSalUfrwbORx8AcYtsqudj9KlzFmf98W8PbwpSUu0axJmDYjHnH35ltYDjiZgX06RMKOSWQILt2O_4P2T1DtKUz0UOLjW04rpbz-pyOuw6sxQMHOQNUsUt_effojsBB6ISA6ejs-DKx652_M0JYMdZ_GnN2CODJdpZQIYI7xTgaOVrJjjzcxeczcMkGMTryS0qN8U4Pjy9Y4TAVTgSDw3Ca-dw-abwI4oY1aZILDEHglcCVcSMC5Vu6uO1BiLTD7Gc7wbMUi05OPxDrv4xumXVYVDpXhM4kENnoK3_gmGZMQ3SvFWAcFahwR-lyb8gisK8gZZ19PG-Iw

This is the latest code I've tried:

 string modulus = "w7Zdfmece8iaB0kiTY8pCtiBtzbptJmP28nSWwtdjRu0f2GFpajvWE4VhfJAjEsOcwYzay7XGN0b-X84BfC8hmCTOj2b2eHT7NsZegFPKRUQzJ9wW8ipn_aDJWMGDuB1XyqT1E7DYqjUCEOD1b4FLpy_xPn6oV_TYOfQ9fZdbE5HGxJUzekuGcOKqOQ8M7wfYHhHHLxGpQVgL0apWuP2gDDOdTtpuld4D2LK1MZK99s9gaSjRHE8JDb1Z4IGhEcEyzkxswVdPndUWzfvWBBWXWxtSUvQGBRkuy1BHOa4sP6FKjWEeeF7gm7UMs2Nm2QUgNZw6xvEDGaLk4KASdIxRQ";
 string exponent = "AQAB";

 try
 {
     IDictionary<string, object> claims = Decode(token, modulus, exponent);
}
catch (SignatureVerificationException ex)
{
     // signature invalid, handle it here
     return false;
}
return true;

private static IDictionary<string, object> Decode(string token, string modulus, string exponent)
{
    var urlEncoder = new JwtBase64UrlEncoder();

    var rsaKey = RSA.Create();
    rsaKey.ImportParameters(new RSAParameters()
        {
            Modulus = urlEncoder.Decode(modulus),
            Exponent = urlEncoder.Decode(exponent)
        });

    var claims = new JwtBuilder()
            .WithAlgorithm(new RS256Algorithm(rsaKey))
            .MustVerifySignature()
            .Decode<IDictionary<string, object>>(token);

    return claims;
}

I get the following error:

The signature is invalid according to the validation procedure.

Now, I don't really know what this modulus and exponent strings are. I just copied them from the example someone gave, so I don't know if it's related to my problem.

This code is also making no use of my secret key.

I did not generate the token myself. A 3rd-party authorization server is generating that.


Solution

  • The modulus and exponent are parts of an RSA key, it is basically trying to recreate the RSA key from known values (whether that works like you have or not I don't know).

    Anyway, you can use instead the JwtSecurityTokenHandler which is in the System.IdentityModel.Tokens.Jwt package. All you have to do then is pass in the relevant parameters directly (the actual RSA key) and it will validate and give you back the valid token if if it succeeds. Something like this:

    SecurityToken validatedToken;
    ClaimsPrincipal principal = validator.ValidateToken(jwtToken, GetValidationParameters(), out validatedToken);
    

    where the validation parameters are like this:

    private TokenValidationParameters GetValidationParameters()
            {
                return new TokenValidationParameters
                {
                    IssuerSigningKey = GetRSAKey(),
                    ValidIssuer = jwtConfig.Issuer,
                    ValidAudience = jwtConfig.Audience,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKeyResolver = GetMethodToResolveExternalKey(),
                    ValidateIssuer = true,
                    ValidateAudience = false,
                    ValidateLifetime = true,
                };
            }
    

    Note that the signing key and the signing key resolver are separate techniques. You can pass the key directly if you have it locally but if you need to look it up somewhere else (like Azure Key Vault) you can pass a method which will be called with the name of the key specified in the JWT token.