'HttpContext.SignInAsync() doesn't authenticate the user

I have been trying to create a custom login feature in ASP.NET Core 2.1. However, it doesn't seem the work and I have no idea why.

This is run in the controller:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Email, email),
    new Claim(ClaimTypes.Role, loginResult.User.RoleName)
};

ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal(identity);
var timespanExpiry = new TimeSpan(0, 0, 30, 0, 0);
await httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme
    , principal
    , new AuthenticationProperties { ExpiresUtc = new DateTimeOffset(timespanExpiry.Ticks, timespanExpiry) });

This is what I have in my Startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddMemoryCache();
            services.AddSingleton<IConfiguration>(Configuration);
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //services
            services.AddSingleton<ITableStorageService, TableStorageService>();

            services.AddAuthorization(options =>
            {
                options.AddPolicy("ConfirmUser", 
                    policy => policy.Requirements.Add(new AuthorizationsRequirement(AuthorizationKeyConstants.AUTH_CONFIRM_USER)));
                options.AddPolicy("GetUser",
                    policy => policy.Requirements.Add(new AuthorizationsRequirement(AuthorizationKeyConstants.AUTH_GET_USER)));
                options.AddPolicy("RemoveUser",
                    policy => policy.Requirements.Add(new AuthorizationsRequirement(AuthorizationKeyConstants.AUTH_DELETE_USER)));
                options.AddPolicy("GetListUser",
                    policy => policy.Requirements.Add(new AuthorizationsRequirement(AuthorizationKeyConstants.AUTH_GETLIST_USER)));
            });

            services.AddAuthentication(options =>
                {
                    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
                {
                    options.LoginPath = new PathString("/User/Login");
                    options.AccessDeniedPath = new PathString("/error?unauth");
                });

            services.AddSingleton<IAuthorizationHandler, AuthorizationsHandler>();

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseAuthentication();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

No errors are occurring, but when I use the code below in Razor or in my controller to check if the user is authenticated, it returns a false. I have checked other questions and answers as well, none of it helps and helped me out with this.

httpContextAccessor.HttpContext.User.Identity.IsAuthenticated

Is there another way to do this, or am I doing something wrong?

EDIT: I have included my whole Startup.cs but excluded some dependency injections and database related information on purpose.



Solution 1:[1]

When adding the cookie you need to pass in the AuthenticationScheme.

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                .AddCookie(
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    options => {
                        options.LoginPath = "/Login";
                    }
                );

Solution 2:[2]

I know this was asked a long time ago, but I recently encountered this same issue. So,here I am sharing my finding.

app.UseHttpsRedirection();
app.UseStaticFiles();
var cookiePolicyOptions = new CookiePolicyOptions
{
   MinimumSameSitePolicy = SameSiteMode.Strict,
   HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always,
   Secure = CookieSecurePolicy.None,
};
    
app.UseCookiePolicy(cookiePolicyOptions);
    
app.UseRouting();
    
app.UseAuthorization();
app.UseAuthentication();

For some reason when I use the above code in startup.cs ,It always redirecting to /login

But the below code is working fine.

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

var cookiePolicyOptions = new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict,
    HttpOnly = Microsoft.AspNetCore.CookiePolicy.HttpOnlyPolicy.Always,
    Secure = CookieSecurePolicy.None,
};
app.UseCookiePolicy(cookiePolicyOptions);
app.UseAuthentication();
app.UseAuthorization();

It seems position of UseRouting() impacts cookie authentication, any comments on this will be appreciated.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 José Yánez
Solution 2 Pronoy Chowdhury