SignatureVerificationFailedException in JwtAuthForWebAPI
Asked Answered
P

2

5

I have wired up the JwtAuthForWebAPI nuget project but I am not able to validate the generated tokens. I end up getting a 500 error. I am using the exact same key value for both token generation and also when configuring JwtAuthenticationMessageHandler.

This is the code to generate a token:

var tokenHandler = new JwtSecurityTokenHandler();
var symmetricKey = JsonWebTokenSecretKey.GetBytes();
var now = DateTime.UtcNow;

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(
        new[]{
            new Claim(JwtClaimKeys.Audience, SessionManager.Current.ApplicationId.ToString()), 
            new Claim(JwtClaimKeys.Subject, userLoginRequest.ApplicationInstanceId.ToString())
        }),
    TokenIssuerName = "My Company",
    Lifetime = new Lifetime(now, now.AddMinutes(tokenLifetimeInMinutes)),
    SigningCredentials = new SigningCredentials(
        new InMemorySymmetricSecurityKey(symmetricKey),
        "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
        "http://www.w3.org/2001/04/xmlenc#sha256")
};

tokenDescriptor.Subject.AddClaims(GetRoles(userLoginRequest));

var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);

This is the code to register the authentication handler:

var keyBuilder = new SecurityTokenBuilder();

var jwtHandler = new JwtAuthenticationMessageHandler
{
    Issuer = "My Company",
    AllowedAudience = ApplicationId.ToString(),
    SigningToken = keyBuilder.CreateFromKey(JsonWebTokenSecretKey),
    PrincipalTransformer = new MyUserPrincipleTransformer()
};

config.MessageHandlers.Add(jwtHandler);

This is the error I get:

{"Message":"An error has occurred.","ExceptionMessage":"IDX10503: Signature validation failed. Keys tried: 'System.IdentityModel.Tokens.InMemorySymmetricSecurityKey\r\n'.\nExceptions caught:\n ''.\ntoken: '{\"typ\":\"JWT\",\"alg\":\"HS256\"}.{\"aud\":\"1\",\"sub\":\"3\",\"role\":[\"User\",\"Admin\"],\"iss\":\"My Company\",\"exp\":1429547369,\"nbf\":1429543769}'","ExceptionType":"System.IdentityModel.SignatureVerificationFailedException",
"StackTrace":"   
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)\r\n   
at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)\r\n   
at JwtAuthForWebAPI.JwtSecurityTokenHandlerAdapter.ValidateToken(IJwtSecurityToken securityToken, TokenValidationParameters validationParameters)\r\n   
at JwtAuthForWebAPI.JwtAuthenticationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n   
at System.Web.Http.HttpServer.<SendAsync>d__0.MoveNext()"}

This is an example JSON token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxIiwic3ViIjoiMyIsInJvbGUiOlsiVXNlciIsIkFkbWluIl0sImlzcyI6Ik15IENvbXBhbnkiLCJleHAiOjE0Mjk1NTE4MjgsIm5iZiI6MTQyOTU0ODIyOH0.9wA_RBir9u7Cn_-Fy2T-Q_IDUfz6B928IEbIgXD9Bug

Interestingly, I am able to validate the token with my key using http://jwt.io. I suspect it may have something to do with the JwtAuthForWebAPI library looking at something different than what the System.Identity JWT library is generating?

Permutation answered 20/4, 2015 at 17:37 Comment(0)
A
7

this is Jamie (author of the JwtAuthForWebAPI package). The server config code - specifically, SecurityTokenBuilder.CreateFromKey(string) - assumes the given string is base64 encoded. It was either that, or assumptions or parameters are needed that would indicate which encoding to use for converting to a byte array. I chose to assume the string was base64 encoded. I'm sure there's a clearer way to go about converting the string key into a SecurityToken, but that's the way the code is today.

In SmokeTests.cs within the JwtAuthForWebAPI.SampleClient project, you can see that I used the Convert.FromBase64String() method, as opposed to using the GetBytes() method from an Encoding class:

public const string SymmetricKey = "YQBiAGMAZABlAGYAZwBoAGkAagBrAGwAbQBuAG8AcABxAHIAcwB0AHUAdgB3AHgAeQB6ADAAMQAyADMANAA1AA==";

// ...

var key = Convert.FromBase64String(SymmetricKey);
var credentials = new SigningCredentials(
    new InMemorySymmetricSecurityKey(key),
    "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
    "http://www.w3.org/2001/04/xmlenc#sha256");

Feel free to keep using your current token generation code, but on the server...

Please try specifying a base64 encoded version of JsonWebTokenSecretKey in the server configuration code. You can use a site like https://www.base64encode.org/ to encode it, or try code like this:

var base64key = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonWebTokenSecretKey));

var keyBuilder = new SecurityTokenBuilder();
var jwtHandler = new JwtAuthenticationMessageHandler
{
    Issuer = "My Company",
    AllowedAudience = ApplicationId.ToString(),
    SigningToken = keyBuilder.CreateFromKey(base64key),
    PrincipalTransformer = new MyUserPrincipleTransformer()
};

Let me know whether or not that works.

Also, I'm going to update the library to catch the SignatureVerificationFailedException exception and return a 401, as opposed to letting an internal server error happen. You'll still need to specify your key as a base64 string, but at least such configuration issues won't cause a 500 error.

Again, please let me know if that does the trick.

Aimee answered 21/4, 2015 at 0:37 Comment(6)
Thank you so much! During the creation of a token I changed it to use this line: var symmetricKey = Convert.FromBase64String(base64Key); and it worked.Permutation
@Aimee - I am facing same issue on production only, its working fine in my dev environment. Please note that I am not using certificatesubject/certificate for any of environments. Also, dev websites are having 'http' and production having 'https' protocols but web Api are not using certificates. The expiration duration for token is 30days but it gets expired within around 30 minutes, any suggestions to drill down this issue?Amu
@gaurav The issue above (from Adam Fisher) was resolved by making sure the symmetric key was provided to the library as a base64 encoded string. Have you tried that? How are you signing the token now - if not using a certificate?Aimee
@Aimee - Now, token is working fine. I met another issue, token life is 30-days. Its strange but once client restart his/her machine then same token (which validated earlier) got invalid. Interestingly, I am able to validate the token with my key using jwt.io Any suggestions?Amu
@Jamie: When I tried to validate an expired token i get internal server error rather than the 401. I am using asp.net core 1. ex: new JwtSecurityTokenHandler().ValidateToken(my-expired-token)Selfcongratulation
@ashraf: I have not tried the library with ASP.NET Core. Do you have any other error information? You can look into additional logging here: github.com/jamiekurtz/JwtAuthForWebAPI#loggingAimee
P
0

it's just my code sample base on @Jamie answer

 protected string GetUsername(string token)
        {
            string secret = "keyyyyy!@3";
           var key = Convert.FromBase64String(secret);

            var IssuerSigningKey = new SymmetricSecurityKey(key);
            IdentityModelEventSource.ShowPII = true;
            var SigningCredentials = new SigningCredentials(
                     IssuerSigningKey,
                     SecurityAlgorithms.HmacSha256Signature);

            var handler = new JwtSecurityTokenHandler();
            var tokenSecure = handler.ReadToken(token) as SecurityToken;
            var validations = new TokenValidationParameters
            {

                ValidateIssuerSigningKey = true,
                IssuerSigningKey = IssuerSigningKey,
                ValidateIssuer = false,
                ValidateAudience = false
            };
            var claims = handler.ValidateToken(token, validations, out tokenSecure);
            return claims.Identity.Name;
        }
Presentational answered 3/10, 2018 at 23:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.