I have been trying to incorporate Identity Server 4 into my ASP.NET Core 3 application and continually get the following error:
No sign-in authentication handler is registered for the scheme 'Identity.Application.
The registered sign-in schemes are: Cookies. Did you forget to call AddAuthentication().AddCookies("Identity.Application",...)
? and I'm not sure what the error means.
I had a look at this SO question, this (Authorize with a specific scheme in ASP.NET Core) MS .NET article, as well as several others, but none have helped.
My Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
var appSettings = appSettingsSection.Get<AppSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
services
.AddAuthentication(x =>
{
x.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme) // , opt => opt.LoginPath = "/Identity"
.AddJwtBearer(opt =>
{
opt.RequireHttpsMetadata = false;
opt.SaveToken = true;
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddIdentityCore<IdentityUser>(opt =>
{
opt.User.RequireUniqueEmail = true;
opt.Password.RequireDigit = true;
opt.Password.RequireLowercase = true;
opt.Password.RequireUppercase = true;
opt.Password.RequireNonAlphanumeric = true;
opt.Password.RequiredLength = 6;
}).AddEntityFrameworkStores<RbIdentityContext>();
// == The original "AddIdentity" method automatically added all of the following
// https://stackoverflow.com/questions/44483589/unable-to-resolve-service-for-type-microsoft-aspnetcore-identity-usermanager-w/48598575/#answer-56551234
services.AddHttpContextAccessor();
// Identity services
services.TryAddScoped<IUserValidator<IdentityUser>, UserValidator<IdentityUser>>();
services.TryAddScoped<IPasswordValidator<IdentityUser>, PasswordValidator<IdentityUser>>();
services.TryAddScoped<IPasswordHasher<IdentityUser>, PasswordHasher<IdentityUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IRoleValidator<IdentityRole>, RoleValidator<IdentityRole>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<IdentityUser>>();
services.TryAddScoped<ITwoFactorSecurityStampValidator, TwoFactorSecurityStampValidator<IdentityUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<IdentityUser>, UserClaimsPrincipalFactory<IdentityUser, IdentityRole>>();
services.TryAddScoped<UserManager<IdentityUser>>();
services.TryAddScoped<SignInManager<IdentityUser>>();
services.TryAddScoped<RoleManager<IdentityRole>>();
//
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
}
My controller contains:
public async Task<IActionResult> Login([FromBody]UserModel model)
{
var result = await _signInMgr.PasswordSignInAsync(model.Email, model.Password, false, false).ConfigureAwait(true);
if (result.Succeeded)
return Ok();
else
return StatusCode(StatusCodes.Status401Unauthorized, JsonConvert.SerializeObject(new { error = ErrorHelper.SetControllerError("Invalid user name or password.") }));
}
The error occurs when executing _signInMgr.PasswordSignInAsync(model.Email, model.Password, false, false)
.
It happens because .AddIdentityCore()
doesn't configure the cookies for you. You'd need to call .AddIdentity()
to have it set up automatically. Otherwise, you have to do it yourself.
.AddAuthentication(x =>
{
x.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(IdentityConstants.ApplicationScheme)
Edit:
To see what is happening inside the service collection extension methods called AddIdentity()
check out the GitHub repo related to this code.