jamiekurtz / JwtAuthForWebAPI

Nuget-deployed library for securing your ASP.NET Web API service with JSON Web Tokens (JWT).
GNU Lesser General Public License v3.0
68 stars 28 forks source link

Unable to Authenticate with Token using tokens from System.IdentityModel.Tokens.Jwt #9

Closed adamfisher closed 9 years ago

adamfisher commented 9 years ago

I am using your library and I successfully generate a JWT token using the System.IdentityModel.Tokens.Jwt official library to generate a token:

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

var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(
        new[]{
            new Claim(JwtClaimKeys.Audience, SessionManager.Current.AppName), 
            new Claim(JwtClaimKeys.Subject, userLoginRequest.UserName),
            new Claim(JwtClaimKeys.Roles, GetRoles(userLoginRequest))
        }),
    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")
};

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

But it says "Authorization has been denied for this request.". I configured the following in my WebAPI startup:

var keyBuilder = new SecurityTokenBuilder();

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

config.MessageHandlers.Add(jwtHandler);
jamiekurtz commented 9 years ago

Hi Adam. Here are some thoughts based on what you included....

Hope that helps. Let me know if not.

On Thu, Apr 16, 2015 at 3:02 PM, Adam notifications@github.com wrote:

I am using your library and I successfully generate a JWT token using the System.IdentityModel.Tokens.Jwt official library to generate a token:

var tokenHandler = new JwtSecurityTokenHandler();var symmetricKey = secretKey.GetBytes();var now = DateTime.UtcNow; var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity( new[]{ new Claim(JwtClaimKeys.Audience, SessionManager.Current.AppName), new Claim(JwtClaimKeys.Subject, userLoginRequest.UserName), new Claim(JwtClaimKeys.Roles, GetRoles(userLoginRequest)) }), 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") }; var token = tokenHandler.CreateToken(tokenDescriptor);return tokenHandler.WriteToken(token);

But it says "Authorization has been denied for this request.". I configured the following in my WebAPI startup:

var keyBuilder = new SecurityTokenBuilder(); var jwtHandler = new JwtAuthenticationMessageHandler { Issuer = "My Company", AllowedAudience = ConfigurationManager.AppSettings[AppSettingKeys.ApplicationId], SigningToken = keyBuilder.CreateFromKey(JsonWebTokenSecretKey), PrincipalTransformer = new MyUserPrincipleTransformer() };

config.MessageHandlers.Add(jwtHandler);

— Reply to this email directly or view it on GitHub https://github.com/jamiekurtz/JwtAuthForWebAPI/issues/9.

adamfisher commented 9 years ago

It's a 401 error in fiddler. I am able to plug my token and signature into http://jwt.io and it says the signature is valid. I suspect it has something to do with the way the key is constructed because when I create the token I use an InMemorySymmetricSecurityKey object and pass the symmetricKey which is already base 64 encoded.

Thanks for the pointer on the roles by the way.

2015-04-17 14:36:07,607 ERROR [50] JwtAuthForWebAPI - Error during JWT validation: System.IdentityModel.SignatureVerificationFailedException: IDX10503: Signature validation failed. Keys tried: 'System.IdentityModel.Tokens.InMemorySymmetricSecurityKey
'.
Exceptions caught:
 ''.
token: '{"typ":"JWT","alg":"HS256"}.{"aud":"1","sub":"3","role":["User","CoCo User"],"iss":"My Company","exp":1429299324,"nbf":1429295724}'
   at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at JwtAuthForWebAPI.JwtSecurityTokenHandlerAdapter.ValidateToken(IJwtSecurityToken securityToken, TokenValidationParameters validationParameters)
   at JwtAuthForWebAPI.JwtAuthenticationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
adamfisher commented 9 years ago

JsonWebTokenSecretKey is base 64 encoded and used the same in both places.

var symmetricKey = DatabaseQuerySettings("JsonWebTokenSecretKey");
JsonWebTokenSecretKey = Convert.ToBase64String(symmetricKey.GetBytes()); //UTF-8 encoded bytes
adamfisher commented 9 years ago

Still not having any luck. I tried manually verifying the token signature and it gave me the principal successfully.

var tokenString = tokenHandler.WriteToken(token);

var validationParameters = new TokenValidationParameters()
{
    ValidIssuer = "My Company",
    ValidAudience = SessionManager.Current.ApplicationId.ToString(),
    IssuerSigningKey = new InMemorySymmetricSecurityKey(symmetricKey)
};

SecurityToken securityToken = new JwtSecurityToken();
tokenHandler = new JwtSecurityTokenHandler();
var principal = tokenHandler.ValidateToken(tokenString, validationParameters, out securityToken);
adamfisher commented 9 years ago

Added StackOverflow question: http://stackoverflow.com/questions/29754662/signatureverificationfailedexception-in-jwtauthforwebapi

jamiekurtz commented 9 years ago

thanks Adam. I'll be looking into this tonight for sure. Sorry... busy weekend!

On Mon, Apr 20, 2015 at 1:42 PM, Adam notifications@github.com wrote:

Added StackOverflow question:

http://stackoverflow.com/questions/29754662/signatureverificationfailedexception-in-jwtauthforwebapi

— Reply to this email directly or view it on GitHub https://github.com/jamiekurtz/JwtAuthForWebAPI/issues/9#issuecomment-94520698 .

jamiekurtz commented 9 years ago

... responded on http://stackoverflow.com/questions/29754662/signatureverificationfailedexception-in-jwtauthforwebapi

Please let me know whether or not that gets you going.

On Mon, Apr 20, 2015 at 3:46 PM, Jamie Kurtz jamie@jamiekurtz.com wrote:

thanks Adam. I'll be looking into this tonight for sure. Sorry... busy weekend!

On Mon, Apr 20, 2015 at 1:42 PM, Adam notifications@github.com wrote:

Added StackOverflow question:

http://stackoverflow.com/questions/29754662/signatureverificationfailedexception-in-jwtauthforwebapi

— Reply to this email directly or view it on GitHub https://github.com/jamiekurtz/JwtAuthForWebAPI/issues/9#issuecomment-94520698 .

adamfisher commented 9 years ago

Thanks for your help Jamie. That got me past the authentication and now it's just a matter of cleaning up some principle transformation bugs. By chamce, is there an API in the library like a delegate or function callback that would allow you to validate custom claims?

adamfisher commented 9 years ago

Mmmmhh. I seemed to have hit a new error. No longer getting the signature verification exception but I'm unable to see what the issue is with the async method. I'll review the code and see if anything stands out.

2015-04-21 15:03:54,716 ERROR [8] JwtAuthForWebAPI - Error during JWT validation: System.NullReferenceException: Object reference not set to an instance of an object. at JwtAuthForWebAPI.JwtAuthenticationMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

jamiekurtz commented 9 years ago

That's a great idea... but doesn't exist right now. I should be able to add that, though, within the next day or two.

On Tue, Apr 21, 2015 at 2:50 PM, Adam notifications@github.com wrote:

Thanks for your help Jamie. That got me past the authentication and now it's just a matter of cleaning up some principle transformation bugs. By chamce, is there an API in the library like a delegate or function callback that would allow you to validate custom claims?

— Reply to this email directly or view it on GitHub https://github.com/jamiekurtz/JwtAuthForWebAPI/issues/9#issuecomment-94902557 .

jamiekurtz commented 9 years ago

Adam - For the NullRef exception.. check that your PrincipalTransform is passing a non-null Identity into the custom principal. I was able to reproduce what I think you're running into by creating a custom principal with a null identity. The error could be coming from line 182 of the JwtAuthenticationMessageHandler class ( https://github.com/jamiekurtz/JwtAuthForWebAPI/blob/master/src/JwtAuthForWebAPI/JwtAuthenticationMessageHandler.cs#L182 )

On Tue, Apr 21, 2015 at 3:30 PM, Jamie Kurtz jamie@jamiekurtz.com wrote:

That's a great idea... but doesn't exist right now. I should be able to add that, though, within the next day or two.

On Tue, Apr 21, 2015 at 2:50 PM, Adam notifications@github.com wrote:

Thanks for your help Jamie. That got me past the authentication and now it's just a matter of cleaning up some principle transformation bugs. By chamce, is there an API in the library like a delegate or function callback that would allow you to validate custom claims?

— Reply to this email directly or view it on GitHub https://github.com/jamiekurtz/JwtAuthForWebAPI/issues/9#issuecomment-94902557 .

adamfisher commented 9 years ago

I found it! This piece of code assumes principal.Identity is non null and mine is null. I forgot to assign the identity in the transformation code.

_logger.DebugFormat("Thread principal set with identity '{0}'", principal.Identity.Name);
adamfisher commented 9 years ago

Thank you for all your help Jamie. I realize not all of the issues I ran into were related to things in your library. I really appreciate it.

As for the callback to validate custom claims, it's not a big deal right now for me. I was trying to use the "aud" claim to store an integer which represents our application ID instead of a URL but Microsoft's identity APIs really want you to specify a URL so I hacked it to be http://mycompany.com/app/231 where 231 is the number I care about. Even when I put the claim in as a custom claim under subject "aud":"231" I suspect it fails validation when the token is coming back in because it uses the Microsoft identity framework to validate it is a URI. The RFC claims this could satisfied as long as there is a colon somewhere in the string but I've found that not to be the case.

In any case, I now have tokens validating successfully. Thanks again for your help :-)

garora commented 8 years ago

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?

jamiekurtz commented 8 years ago

@garora What's the issue you're facing? What's the error message? How are you signing the token you generate?

garora commented 8 years ago

Generation process is same as mentioned in example and herehttp://stackoverflow.com/questions/29754662/signatureverificationfailedexception-in-jwtauthforwebapi The only thing is I am not using Certificate. My 30days token get invalidated after 20-25 minutes. Getting exception- invalid token

jamiekurtz commented 8 years ago

@garora 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?

garora commented 8 years ago

@jamiekurtz - Thanks for your prompt reply. I am following base64 encoded string. Here is the case, I am getting exception:

I've re-written the whole code but still its happening.

jamiekurtz commented 8 years ago

Is this still an issue, @garora ? If so, can you share your token-creation code?

garora commented 8 years ago

@jamiekurtz - this issue has been resolved, when I re-wrote the code. Not sure, how but the new code is same as earlier. Thanks