Search code examples
c#asp.netidentityserver4

ASP.NET Core 3 No Sign-In Manager Is Registered for the Scheme


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).


Solution

  • 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.