IDX10503: Signature validation failed
If you're generating a new RSA key each time you (re)start your server, then it's not surprising: tokens signed with KEY A
cannot be validated using KEY B
. For your scenario to work, you need to store your RSA key somewhere and use the same one during startup.
One way is to call rsa.ExportParameters(true)
and store the different parameters somewhere, so you can easily retrieve and import them using rsa.ImportParameters(...)
.
But your best option is to use AspNet.Security.OpenIdConnect.Server
, that will automatically generate and store a RSA key for you in the last version:
Startup.cs
public class Startup {
public void ConfigureServices(IServiceCollection services) {
services.AddAuthentication();
services.AddCaching();
}
public void Configure(IApplicationBuilder app) {
// Add a new middleware validating access tokens issued by the OIDC server.
app.UseJwtBearerAuthentication(options => {
options.AutomaticAuthentication = true;
options.Authority = "resource_server_1";
options.RequireHttpsMetadata = false;
});
// Add a new middleware issuing tokens.
app.UseOpenIdConnectServer(options => {
options.AllowInsecureHttp = true;
options.Provider = new OpenIdConnectServerProvider {
// Override OnValidateClientAuthentication to skip client authentication.
OnValidateClientAuthentication = context => {
// Call Skipped() since JS applications cannot keep their credentials secret.
context.Skipped();
return Task.FromResult<object>(null);
},
// Override OnGrantResourceOwnerCredentials to support grant_type=password.
OnGrantResourceOwnerCredentials = context => {
// Do your credentials validation here.
// Note: you can call Rejected() with a message
// to indicate that authentication failed.
var identity = new ClaimsIdentity(OpenIdConnectDefaults.AuthenticationScheme);
identity.AddClaim(ClaimTypes.NameIdentifier, "todo");
// By default, claims are not serialized in the access and identity tokens.
// Use the overload taking a "destination" to make sure your claims
// are correctly inserted in the appropriate tokens.
identity.AddClaim("urn:customclaim", "value", "token id_token");
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
context.Options.AuthenticationScheme);
// Call SetResources with the list of resource servers
// the access token should be issued for.
ticket.SetResources(new[] { "resource_server_1" });
// Call SetScopes with the list of scopes you want to grant
// (specify offline_access to issue a refresh token).
ticket.SetScopes(new[] { "profile", "offline_access" });
context.Validated(ticket);
return Task.FromResult<object>(null);
}
}
});
app.UseMvc();
}
}
project.json
{
"dependencies": {
"Microsoft.AspNet.Server.WebListener": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-rc1-final",
"AspNet.Security.OpenIdConnect.Server": "1.0.0-beta4"
}
}
Son_of_Sam
Father, Husband and Coder (all hobbies are in here) and should be the order of life. Son Of Sam is just a bad nick name from my time playing counter strike sorry about that. Love VB because it make sense #SOreadytohelp
Updated on June 05, 2022Comments
-
Son_of_Sam almost 2 years
I getting the following error with a valid token after the application re-start or publish
IDX10503: Signature validation failed. Keys tried: 'System.IdentityModel.Tokens.RsaSecurityKey Exceptions caught: token: '{"typ":"JWT","alg":"RS256","kid":null}.{"unique_name":"[email protected]","iss":"XXXXXX","aud":"XXXXX","exp":1444876186}'
This is the function that generate the KEY
private void generateRsaKeys() { using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048)) { key = new RsaSecurityKey(rsa.ExportParameters(true)); credentials = new SigningCredentials (key,SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest); rsa.PersistKeyInCsp = true; } }
This is how the configuration is done
services.ConfigureOAuthBearerAuthentication(options => { options.AutomaticAuthentication = true; options.TokenValidationParameters.IssuerSigningKey = generateRsaKeys(); options.TokenValidationParameters.ValidAudience = audience; options.TokenValidationParameters.ValidIssuer = issuer; }); app.UseStaticFiles(); app.UseOAuthBearerAuthentication(); // Add MVC to the request pipeline. app.UseMvc();
and this is the action on my controller
// POST: /token [HttpPost()] public async Task<IActionResult> Token([FromBody] LoginModel model) { if (!ModelState.IsValid) return HttpBadRequest(); JwtSecurityTokenHandler handler = _bearerOptions.SecurityTokenValidators.OfType<JwtSecurityTokenHandler>().First(); try { var user = await _Repo.GetDetailAsync(model.Email); if (!model.Password.Equals(user.Password)) return HttpUnauthorized(); JwtSecurityToken securityToken = handler.CreateToken ( issuer: _bearerOptions.TokenValidationParameters.ValidIssuer, audience: _bearerOptions.TokenValidationParameters.ValidAudience, signingCredentials: _signingCredentials, subject: new ClaimsIdentity(new Claim[] { new Claim(ClaimTypes.Name, user.Email) }), expires: DateTime.Now.AddMinutes(2) ); string token = handler.WriteToken(securityToken); return new ObjectResult(new TokenModel() { AccessToken = token, TokenType = "bearer" }); } catch (Exception ex) { // TODO: add loggin logic here return HttpUnauthorized(); } }