✅ JTI not being pulled from payload when I am trying to validate token
I create an access token store all the claims i want on it and get an access token and this is what the payload looks like when its decoded
Creating Access Token
private string CreateAccessToken(ApplicationUser user, string sessionId)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSecret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.UserName.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, sessionId),
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
}),
Expires = DateTime.UtcNow.AddMinutes(30),
SigningCredentials = new(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Issuer = "https://localhost:7059",
Audience = "http://localhost:5173"
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenStr = tokenHandler.WriteToken(token);
return tokenStr;
}
private string CreateAccessToken(ApplicationUser user, string sessionId)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSecret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user.UserName.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, sessionId),
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
}),
Expires = DateTime.UtcNow.AddMinutes(30),
SigningCredentials = new(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Issuer = "https://localhost:7059",
Audience = "http://localhost:5173"
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenStr = tokenHandler.WriteToken(token);
return tokenStr;
}
{
"unique_name": "Test",
"jti": "SESS73ab5ea8-2c67-42a9-ba6e-96241dad5b0a",
"sub": "bababf79-a2bc-49b3-9690-206acd714bd0",
"nbf": 1732389177,
"exp": 1732390948,
"iat": 1732389177,
"iss": "https://localhost:7059",
"aud": "http://localhost:5173"
}
{
"unique_name": "Test",
"jti": "SESS73ab5ea8-2c67-42a9-ba6e-96241dad5b0a",
"sub": "bababf79-a2bc-49b3-9690-206acd714bd0",
"nbf": 1732389177,
"exp": 1732390948,
"iat": 1732389177,
"iss": "https://localhost:7059",
"aud": "http://localhost:5173"
}
3 Replies
Now when I go to verify that access token for some reason half the claims just dissapear, and i have no idea why
The JIT claim is never present but its present on the incoming access token. and my debugger says only these claims are present
Figured it out
private bool CheckIfAccessTokenIsValid(string accessToken, string expectedUserId, string expectedSessionId)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwt = tokenHandler.ReadJwtToken(accessToken);
var sessionId = jwt.Claims.FirstOrDefault(claim => claim.Type == JwtRegisteredClaimNames.Jti).Value;
var userId = jwt.Claims.FirstOrDefault(claim => claim.Type == JwtRegisteredClaimNames.Sub).Value;
return userId == expectedUserId && sessionId == expectedSessionId;
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
return false;
}
}
private bool CheckIfAccessTokenIsValid(string accessToken, string expectedUserId, string expectedSessionId)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwt = tokenHandler.ReadJwtToken(accessToken);
var sessionId = jwt.Claims.FirstOrDefault(claim => claim.Type == JwtRegisteredClaimNames.Jti).Value;
var userId = jwt.Claims.FirstOrDefault(claim => claim.Type == JwtRegisteredClaimNames.Sub).Value;
return userId == expectedUserId && sessionId == expectedSessionId;
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
return false;
}
}
{
"unique_name": "Test",
"sub": "bababf79-a2bc-49b3-9690-206acd714bd0",
"exp": 1732390948,
"iat": 1732389177,
"iss": "https://localhost:7059",
}
{
"unique_name": "Test",
"sub": "bababf79-a2bc-49b3-9690-206acd714bd0",
"exp": 1732390948,
"iat": 1732389177,
"iss": "https://localhost:7059",
}
What was it? I read your post and it got me curious, as I recently did something similar and had no issue.
Sorry never got a notification for this, The issue was a variety of things tbh but the way I ended up fixing it was using a different package for jwt's
So instead of using
And these are the packages
JwtSecurityTokenHandler
, i used JsonWebTokenHandler
which is apparently the newer and prefered way to do Jwt's and then changes a few other things you'd have to do since the methods from that handler are async.
So the two methods completely changed to work now look like this
private string CreateAccessToken(ApplicationUser user, string sessionId)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSecret));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var tokenDescriptor = new SecurityTokenDescriptor()
{
Subject = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, sessionId),
}
),
Expires = DateTime.UtcNow.AddMinutes(30),
SigningCredentials = credentials,
Audience = _jwtAudience,
Issuer = _jwtIssuer
};
var tokenHandler = new JsonWebTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return token;
}
private string CreateAccessToken(ApplicationUser user, string sessionId)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSecret));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var tokenDescriptor = new SecurityTokenDescriptor()
{
Subject = new ClaimsIdentity(new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
new Claim(JwtRegisteredClaimNames.Jti, sessionId),
}
),
Expires = DateTime.UtcNow.AddMinutes(30),
SigningCredentials = credentials,
Audience = _jwtAudience,
Issuer = _jwtIssuer
};
var tokenHandler = new JsonWebTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return token;
}
private async Task<bool> CheckIfAccessTokenIsValid(string accessToken, string expectedUserId,
string expectedSessionId)
{
try
{
var tokenHandler = new JsonWebTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSecret);
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ClockSkew = TimeSpan.Zero
};
var tokenValidationResult = await tokenHandler.ValidateTokenAsync(accessToken, tokenValidationParameters);
var userId = tokenValidationResult.Claims.FirstOrDefault(c => c.Key == "sub").Value?.ToString();
var sessionId = tokenValidationResult.Claims.FirstOrDefault(c => c.Key == "jti").Value?.ToString();
return userId == expectedUserId && sessionId == expectedSessionId;
}
catch
{
return false;
}
}
private async Task<bool> CheckIfAccessTokenIsValid(string accessToken, string expectedUserId,
string expectedSessionId)
{
try
{
var tokenHandler = new JsonWebTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtSecret);
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ClockSkew = TimeSpan.Zero
};
var tokenValidationResult = await tokenHandler.ValidateTokenAsync(accessToken, tokenValidationParameters);
var userId = tokenValidationResult.Claims.FirstOrDefault(c => c.Key == "sub").Value?.ToString();
var sessionId = tokenValidationResult.Claims.FirstOrDefault(c => c.Key == "jti").Value?.ToString();
return userId == expectedUserId && sessionId == expectedSessionId;
}
catch
{
return false;
}
}
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.11" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.2.1" />