Stack Overflow Asked by Question3r on December 3, 2021
I’m using the Microsoft.AspNetCore.Authentication.JwtBearer and System.IdentityModel.Tokens.Jwt for my .NET Core project.
Whenever I generate a new token I store that to the database. First of all this is how I generate a new token
public string GenerateToken(Dictionary<string, object> payload)
{
DateTime tokenExpiresAt = DateTime.Now.AddMilliseconds(1); // from config
byte[] symmetricKey = Convert.FromBase64String("secret"); // from config
SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(symmetricKey);
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
{
Claims = payload,
Expires = tokenExpiresAt,
SigningCredentials = new SigningCredentials(symmetricSecurityKey,
SecurityAlgorithms.HmacSha256Signature)
};
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
string token = tokenHandler.WriteToken(securityToken);
return token;
}
The generated sample token is
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwibmJmIjoxNTk1NDQ1NjMxLCJleHAiOjE1OTU0NDU2OTEsImlhdCI6MTU5NTQ0NTYzMX0.cWvSpKC_yYao2_ziW_ahjjHpUl2SgUZvCmsjXntxCOI
If a client tries to access a protected endpoint the default configuration will handle the basic validation (configured in the DI setup in the Startup file)
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtBearerOptions =>
{
byte[] symmetricKey = Convert.FromBase64String("secret"); // from config
SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(symmetricKey);
jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidateIssuer = false,
ValidateAudience = false,
IssuerSigningKey = symmetricSecurityKey,
};
jwtBearerOptions.Events = new JwtBearerEvents()
{
OnTokenValidated = ProcessAfterTokenValidation
};
});
As you can see I added a method to the OnTokenValidated
event listener. This method should check, if the token exists in the database.
public async Task ProcessAfterTokenValidation(TokenValidatedContext tokenValidatedContext)
{
JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
string token = jwtSecurityTokenHandler.WriteToken(tokenValidatedContext.SecurityToken);
// ... check if token exists in db ...
}
The problem with that method is that the generated token is not the exact token as it is stored in the database. There is missing a last segment. The token variable holds this
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwibmJmIjoxNTk1NDQ1NjMxLCJleHAiOjE1OTU0NDU2OTEsImlhdCI6MTU5NTQ0NTYzMX0.
and the missing last part would be
cWvSpKC_yYao2_ziW_ahjjHpUl2SgUZvCmsjXntxCOI
Does someone know why the last part of the token is missing?
Thanks for help!
The last part of the token is the signature. The purpose of the OnTokenValidated method is to provide a ClaimsIdentity. The signature is not a component of the claims of the token holder.
If you had a key rotation policy on the issuing side a given user could present identical claims with a different signature before and after a key rotation.
The identity of the user is derived from a combination of the issuer plus any claims that identify the user (e.g. username
in the token from your example).
In your case, since you are the issuer, the token minus the signature simply represents proof that the user has successfully authenticated against your token issuing endpoint. The claims within the token should lead to a database record rather than the token itself.
Answered by bpdohall on December 3, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP