asp.netauthenticationauthorizationjwtlifetime

JWT token exception in ASP.Net (Lifetime validation failed. The token is missing an Expiration Time.)


I am creating my own custom authentication on ASP. Net MobileService deployed on Azure. I use JWT tokens. Here is how I generate a new token (claimType = email):

    public static string GetSecurityToken(String email)
    {
        var symmetricKey = Convert.FromBase64String(signingKey);
        var tokenHandler = new JwtSecurityTokenHandler();

        var now = DateTime.UtcNow;
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(new[]
                    {
                    new Claim(ClaimTypes.Email, email)
                }),
            NotBefore = now,
            Expires = now.AddYears(10),
            Issuer = issuer,
            Audience = audience,
            IssuedAt = now,
            SigningCredentials = new SigningCredentials(
                new SymmetricSecurityKey(symmetricKey),
                SecurityAlgorithms.HmacSha256Signature),
        };

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

        return token;
    }

The token is sent to the client and stored. But when I try to authorize a message based on its token, I get the error:

Lifetime validation failed. The token is missing an Expiration Time.

This is how I try to validate the token:

    public static ClaimsPrincipal GetPrincipal(string token)
    {
        try
        {
            var tokenHandler = new JwtSecurityTokenHandler();                
            var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;
            
            if (jwtToken == null)
                return null;

            var symmetricKey = Convert.FromBase64String(signingKey);

            Debug.WriteLine(String.Format("JWTManager > GetPrincipal > Validating Token: {0}", token));
            foreach (Claim claim in jwtToken.Claims)
            {
                Debug.WriteLine(String.Format("JWTManager > GetPrincipal > Claims: {0}", claim.ToString()));
            }
            
            var validationParameters = new TokenValidationParameters()
            {
                //RequireExpirationTime = true,
                //ValidateLifetime = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                IssuerSigningKey = new SymmetricSecurityKey(symmetricKey),
            };
            
            SecurityToken securityToken;
            var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
            if (principal != null)
                Debug.WriteLine(String.Format("JWTManager > GetPrincipal > Principal: {0}", principal));
            return principal;
        }
        catch (SecurityTokenException ex)
        {
            Debug.WriteLine(String.Format("JWTManager > GetPrincipal: {0}", ex.Message));
            return null;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(String.Format("JWTManager > GetPrincipal: {0}", ex.Message));
            return null;
        }
    }

Exception is thrown on executing tokenHandler.ValidateToken and null is returned to principal.

My assumption is that maybe I am not setting the Expires and Issuers properties correctly and the TokenHanlder fails to validate them. However, when I check the jwtToken, all the claims are correctly set.

Here is the complete debug output:

JWTManager > GetPrincipal > Claims: email: testEmail@email.com

JWTManager > GetPrincipal > Claims: nbf: 1494752301

JWTManager > GetPrincipal > Claims: exp: 33051661101

JWTManager > GetPrincipal > Claims: iat: 1494752301

JWTManager > GetPrincipal > Claims: iss: MASKED

JWTManager > GetPrincipal > Claims: aud: MAKSED

JWTManager > GetPrincipal: IDX10225: Lifetime validation failed. The token is missing an Expiration Time. Application: Tokentype:


Solution

  • Following the suggestion here, I fixed the problem by switching from using

    System.IdentityModel.Tokens.Jwt.TokenHandler.CreateToken(SecurityTokenDescriptor)

    to

    new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(JwtHeader, JwtPayload).

    And defined the payload as follows:

    DateTime centuryBegin = new DateTime(1970, 1, 1);
    var exp = new TimeSpan(DateTime.Now.AddYears(1).Ticks - centuryBegin.Ticks).TotalSeconds;
    var now = new TimeSpan(DateTime.Now.Ticks - centuryBegin.Ticks).TotalSeconds;
    var payload = new System.IdentityModel.Tokens.Jwt.JwtPayload
    {
        {"iss", issuer},
        {"aud", audience},
        {"iat", (long)now},
        {"exp", (long)exp}
    };
    

    So, I ended up not using the SecurityTokenDescriptor class because it expects DateTime objects to be assigned to Expirs and IssuedAt, or Lifetime properties (depending on whether it is in the Microsoft.IdentityModel.Tokens or System.IdentityModel.Tokens namespace).

    I have no intention of using SecurityTokenDescriptor; however, I couldn't find a solution on how to use SecurityTokenDescriptor and still set correct values to the "exp" field.