7

So this whole JWT signing and validation is quite new to me. I now have an C# application which is requesting some information via an API secured with JWT. Weird thing is that every other request fails. So the first request works like a charm. I'm getting the info and responses I expect. JWT validation is successful.

The next request i do after it (starting the whole process form start. inclusive getting a new accesstoken since the refreshtoken is not supported) I get an 'idx10503 signature validation failed. token does not have a kid'. I can't get my head around it. The JWT.io debugger says the signature is valid.

If after the failed validation I do a new request (again starting the whole process) the JWT is valid.

So, to make it clear, it looks like this:

  • Request 1, JWT validation success.
  • Request 2, JWT validation fail.
  • Request 3, JWT validation success.
  • Request 4, JWT validation fail.
  • etc.

The part where I validate my JWT and get the error is below:

            try
            {
                var keyBytes = Convert.FromBase64String(publicKey);

                AsymmetricKeyParameter asymmetricKeyParameter = PublicKeyFactory.CreateKey(keyBytes);
                RsaKeyParameters rsaKeyParameters = (RsaKeyParameters)asymmetricKeyParameter;
                RSAParameters rsaParameters = new RSAParameters
                {
                    Modulus = rsaKeyParameters.Modulus.ToByteArrayUnsigned(),
                    Exponent = rsaKeyParameters.Exponent.ToByteArrayUnsigned()
                };

                using (var rsa = new RSACryptoServiceProvider())
                {
                    rsa.ImportParameters(rsaParameters);
                    var validationParameters = new TokenValidationParameters()
                    {
                        RequireExpirationTime = true,
                        RequireSignedTokens = true,
                        ValidateAudience = false,
                        ValidateIssuer = false,
                        IssuerSigningKey = new RsaSecurityKey(rsa)
                    };
                    var handler = new JwtSecurityTokenHandler();

                    handler.ValidateToken(jwtToken, validationParameters, out var validatedToken);                    
                }

                return validatedToken;
            }
            catch (Exception e)
            {
                throw e;
            }

I have already tried to see if it makes a difference if I put the RSAParameters in the cache and use those same parameters in the next request. Unfortunatly that makes it worse in my case because all the next JWT validations fail.

Does anyone have an idea what might go wrong?

Willem
  • 398
  • 1
  • 6
  • 23
  • `kid` is a claim that should be in the header of the JWT. Are you sure that each JWT that you send to the API has this claim? Maybe it's a problem with issuing the tokens, not validating them? – Michal Trojanowski May 11 '21 at 10:57
  • Thanks for your reply @MichalTrojanowski, each of the requests goes through the same processes so I expect every request looks the same with slight details ofcourse. But I'll check to make sure it all looks the same so this won't be the issue. – Willem May 12 '21 at 07:11

3 Answers3

5

Fixed my issue finally by adding some parameters to the validationParameters;

TryAllIssuerSigningKeys = true,
IssuerSigningKey = new RsaSecurityKey(rsa),
IssuerSigningKeys = new List<SecurityKey>() { new RsaSecurityKey(rsa) }
Willem
  • 398
  • 1
  • 6
  • 23
  • 1
    Your solution works in my very similar case! In my case, another "solution" was to never dispose the `RSACryptoServiceProvider` (which in your case would correspond to dropping the `using`-keyword). Despite long web searches, I found no satisfactory explanation for the issue. How did you find your solution, and do you know _why_ it works? – Carsten Führmann Jan 03 '22 at 17:36
  • 1
    @CarstenFührmann after long websearches I started to deepdive in every parameter which could be used in the TokenValidationParameters. Then found these three parameters which via the description gave me a hint. Tried it, worked for me. The reason why it works is still not clear to me.. – Willem Jan 06 '22 at 10:51
  • 1
    I added those parameters but I'm still having the same problem. IDX10503. My token is from adfs. If I use and Azure token, it works because it has a kid field. The older version of System.IdentityModel.Tokens worked with these adfs tokens without a kid field. – Jason Cheng Mar 25 '22 at 02:47
2

For anyone else who has this issue, it was because I had updated my Microsoft.EntityFrameworkCore.SqlServer Nuget package from v.5.0.6 to v.6.0.7 which updated Microsoft.Data.Sqlclient from v2.0.1 to v2.1.4 which in turn updated System.Identity.Model from v4.14.0 to to v4.21.1. Rolling back to Microsoft.EntityFrameworkCore.SqlServer v.5.0.6 removed the issue. It looks like System.Identity.Model is updated in EntityFrameworkCore >= v6.0

The lesson here is to always read what Nuget is telling you when installing packages!

batface
  • 21
  • 3
1

I solved my problem which was the same error message as the OP had. It turns out I was using the wrong certificate. The error message is extremely misleading. If the "kid" field is non-existent and you're using the wrong cert, you'll get that incorrect IDX10503 error. I looked at the .net source code and it uses the x5t field if the kid field is missing. Also, I didn't implement OP's fix but it still worked.

Jason Cheng
  • 180
  • 2
  • 12