Search code examples
c#jwt

JWT Validation fails


I have created a JWT token by setting up the payload as shown below:

var payload = new JwtPayload
        {
            {"aud", "wellmark.com" },
            {"iss", "wellmark" },
            {"iat", DateTime.Now.Ticks },
            {"exp", DateTime.Now.AddDays(90).Ticks },
        };

The reason I had to use ticks is because that is the only way to get an integer value for the issued at and expiration times. I agree that ticks need a long and not an int, but that was the only way.

Now when I come back to validate the token, I am doing the below:

var tokenValidationParams = new TokenValidationParameters
            {
                IssuerSigningKey = new X509SecurityKey(jwtCert),
                ValidAudience = "masked",
                ValidIssuer = "masked",
                IssuerSigningKeyResolver = (string token, Microsoft.IdentityModel.Tokens.SecurityToken securityToken, string kid, TokenValidationParameters validationParameters) => new List<X509SecurityKey> { new X509SecurityKey(jwtCert) }
            };

            tokenHandler.ValidateToken(id, tokenValidationParams
                   , out validatedToken);

It is however failing saying

Lifetime validation failed. The token is missing an Expiration Time. Tokentype: 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken'.

This is most likely because the validation method is trying to convert the long to an int and because it is unable to convert it, it simply returns a null as indicated in the documentation shown here.

Has anyone had success with this mechanism? Please note that I am using X509 Certificate to Sign my Jwt.


Solution

  • You can't use Ticks for the exp timestamp

    The timestamps in JWT are UNIX timestamps counting from 01.01.1970 00:00 UTC: https://www.rfc-editor.org/rfc/rfc7519#section-4.1.4 explains that a numeric date is used for the exp claim (and also for the nbf (not before) and iat (issued at) claims)

    https://www.rfc-editor.org/rfc/rfc7519#section-2 defines the numeric date:

    A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds.

    If you create the payload directly like you did in your example you need to calculate the seconds since 1.1.1970 UTC for example like this:

    DateTime centuryBegin = new DateTime(1970, 1, 1);
    var exp = new TimeSpan(DateTime.Now.AddDays(90).Ticks - centuryBegin.Ticks).TotalSeconds;
    

    exp is then 90 days from now. Of course you can use any of the other Add... methods as well to calculate the expriation time. Refer to https://msdn.microsoft.com/de-de/library/system.datetimeoffset(v=vs.110).aspx to see the other Add methods.

    Some frameworks (e.g. System.IdentityModel.Tokens.Jwt) offer functions to create tokens which accept parameters of the type DateTimeOffset, which is easier to handle.

    Use http://www.unixtimestamp.com/ or similar sites to check your timestamps