Search code examples
c#asp.net-coreasp.net-identityjson-web-token

UseJwtBearerAuthentication fails with IDX10504: Unable to validate signature, token does not have a signature


Using ASP.NET Core 1.0 (rtm), with the somewhat minimal verifiable sample that I have produced, I am seeing that the JSON Web Tokens I produce are not passing the .net core json web token middleware claim challenge, and are failing with this error:

Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: 
IDX10504: Unable to validate signature, token does not have a signature: 
'... ... token value here...'

I have produced a minimal sample, which worked fine in ASP.NET Core RC1, but which does not work in RTM. I did not port to RC2 to test, but I believe that such a test is pointless. You can exercise the demo with a provided test script:

 python tests\testloginapi.py
  GET OK: 200 http://localhost:54993/authorize/login?username=TEST&pas...
  POST OK: 200 http://localhost:54993/authorize/login?username=TEST&pas...
  authorization token received... eyJhbGciOi...
  expected status 200 but got 401 for GET http://localhost:54993/authorizetest/test

Salient points of my minimal example are:

Startup.cs method Configure has:

        app.UseJwtBearerAuthentication(_keyArtifacts.getJwtBearerOptions());

The bearer options are like this:

  public static JwtBearerOptions CreateJwtBearerOption(RsaSecurityKey key, string tokenIssuer, string tokenAudience)
        {
            var jwtBearerOptions = new JwtBearerOptions();


            jwtBearerOptions.AutomaticAuthenticate = true;
            jwtBearerOptions.AutomaticChallenge = true;
            jwtBearerOptions.TokenValidationParameters.ValidateIssuerSigningKey = true;
            jwtBearerOptions.TokenValidationParameters.IssuerSigningKey = key;
            jwtBearerOptions.TokenValidationParameters.ValidIssuer = tokenIssuer;
            jwtBearerOptions.TokenValidationParameters.ValidateIssuer = true;
            jwtBearerOptions.TokenValidationParameters.ValidateLifetime = true;
            jwtBearerOptions.TokenValidationParameters.ClockSkew = TimeSpan.Zero;



            jwtBearerOptions.TokenValidationParameters.ValidAudience = tokenAudience;
            return jwtBearerOptions;
        }

This question really boils down to:

  1. In Asp.net core 1.0 rtm, what are the minimal steps to create a token that will pass the middleware challenge?

  2. Am I simply missing some simple step (as little as one line of code perhaps) that would make this demo work, including having "signing" work?

  3. Given that the demo is still a horrible piece of code, and nobody should ever use it in production (because I'm already ashamed of it), my hope is this question can still be illuminating as to how to make the UseJwtBearerAuthentication system actually work, at least at a demo scale.


Solution

  • In Asp.net core 1.0 rtm, what are the minimal steps to create a token that will pass the middleware challenge? Am I simply missing some simple step (as little as one line of code perhaps) that would make this demo work, including having "signing" work?

    IdentityModel (the library responsible for validating the tokens received by the JWT bearer middleware) is unable to validate your JWT tokens because they effectively don't have any signature, as explained in the error you're seeing.

    The lack of signature is likely caused by the fact you're not assigning SecurityTokenDescriptor.SigningCredentials when creating your own tokens:

    JwtSecurityTokenHandler handler = BearerOptions
        .SecurityTokenValidators
        .OfType<JwtSecurityTokenHandler>()
        .First();
    
    var tokenData = new SecurityTokenDescriptor
    {
        
        Issuer = BearerOptions.TokenValidationParameters.ValidIssuer,
        Audience = BearerOptions.TokenValidationParameters.ValidAudience,
        Subject = new ClaimsIdentity(claims),
        Expires = DateTime.Now.AddDays(1),
        NotBefore = DateTime.Now
    };
    
    /*JwtSecurityToken*/
    var securityToken =
        handler.CreateToken
        (
            tokenData
        );
    

    Fix that, and it should work.

    Given that the demo is still a horrible piece of code, and nobody should ever use it in production (because I'm already ashamed of it), my hope is this question can still be illuminating as to how to make the UseJwtBearerAuthentication system actually work, at least at a demo scale.

    Actually, the problem is not how you use the JWT bearer middleware but how you generate your own tokens. Implementing your own token issuer sauce is fine, but using a standard like OAuth 2.0 or OpenID Connect is generally better and easier to use (e.g when having an OIDC server, you don't have to configure the JWT bearer middleware as it will directly download the signing keys using OIDC discovery).

    Feel free to read this other SO answer for more information.