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?

Adam
  • 4,590
  • 10
  • 51
  • 84

2 Answers2

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.

Jamie
  • 141
  • 2
  • 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. – Adam Apr 21 '15 at 18:48
  • @Jamie - 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? – Gaurav Arora Dec 29 '15 at 08:26
  • @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? – Jamie Jan 05 '16 at 12:58
  • @Jamie - 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 http://jwt.io Any suggestions? – Gaurav Arora Jan 20 '16 at 08:04
  • @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) – ashraf Oct 07 '16 at 16:51
  • @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: https://github.com/jamiekurtz/JwtAuthForWebAPI#logging – Jamie Oct 11 '16 at 00:00
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;
        }
Amirreza
  • 575
  • 9
  • 25