Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Core 2.0 Cookie Authentication

0.00/5 (No votes)
8 Sep 2017 1  
How to implement cookie authentication in ASP.NET Core 2.0 Continue reading...

Problem

How to implement cookie authentication in ASP.NET Core 2.0.

Solution

Create an empty project and update Startup to configure services and middleware for MVC and Authentication:

public void ConfigureServices(
            IServiceCollection services)
        {
            services.AddAuthentication("FiverSecurityScheme")
                    .AddCookie("FiverSecurityScheme", options =>
                    {
                        options.AccessDeniedPath = new PathString("/Security/Access");
                        options.LoginPath = new PathString("/Security/Login");
                    });

            services.AddMvc();
        }

        public void Configure(
            IApplicationBuilder app,
            IHostingEnvironment env)
        {
            app.UseAuthentication();

            app.UseMvcWithDefaultRoute();
        }

Create a model to receive login details:

public class LoginInputModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }

Create a login page:

<form asp-controller="Security" asp-action="Login" method="post">
    <input type="text" name="username" id="username" />
    <input type="password" name="password" id="password" />
    <input type="submit" value="Login" />
</form>

Create a controller for Login and Logout actions:

public IActionResult Login()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> Login(LoginInputModel inputModel)
        {
            if (!IsAuthentic(inputModel.Username, inputModel.Password))
                return View();

            // create claims
            List<Claim> claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "Sean Connery"),
                new Claim(ClaimTypes.Email, inputModel.Username)
            };

            // create identity
            ClaimsIdentity identity = new ClaimsIdentity(claims, "cookie");

            // create principal
            ClaimsPrincipal principal = new ClaimsPrincipal(identity);

            // sign-in
            await HttpContext.SignInAsync(
                    scheme: "FiverSecurityCookie",
                    principal: principal);
            
            return RedirectToAction("Index", "Home");
        }

        public async Task<IActionResult> Logout()
        {
            await HttpContext.SignOutAsync(
                    scheme: "FiverSecurityCookie");

            return RedirectToAction("Login");
        }

Finally, add a controller to secure using [Authorize] attribute:

[Authorize]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }

Discussion

Authentication middleware intercepts incoming requests and checks for the existence of a cookie holding encrypted user data.

  • If a cookie is found, it will be serialized into a ClaimsPincipal type and can be accessed via HttpContext.User property.
  • If a cookie isn’t found, middleware redirects to login page using an action method. Through the login page, you’ll receive user details and authenticate against your database records. Once authenticated, you’ll need to:
    • Create List<Claim> related to the user identity.
    • Create ClaimsIdentity, assign claims and specify authentication type.
    • Create ClaimsPrincipal and assign identity.
    • Call HttpContext.SignInAsync() with authentication scheme name (setup via services, see next section) and Principal.

Cookie Authentication Options

When setting up cookie services, there are several options to tweak its behaviour like:

  • AccessDeniedPath: Redirects to this path when authorization fails
  • AuthenticationScheme: Name that identifies the scheme, used with signing in and out. In the solution, it’s FiverSecurityScheme
  • Cookie.Domain: Domain used for cookie storage, defaults to request’s host. Browser will only send cookie to matching host
  • Cookie.HttpOnly: Sets whether cookie can be accessed from client side scripts. Default is true, i.e., only accessed via HTTP and not via scripts
  • Cookie.Name: Set to override default name of cookie, which is .AspNetCore.Cookies
  • Cookie.Path: Path where cookie is created, default is ‘/’, i.e., root
  • Cookie.SecurePolicy: Determines if cookie can be accessed via HTTPS requests only
  • ExpireTimeSpan: Determines how long the cookie is valid for
  • LoginPath: Redirects to this page for unauthenticated users
  • ReturnUrlParameter: Name of query string parameter appended to URL when redirected to login path
  • SlidingExpiration: Set to keep the cookie alive once close to expiry time (half way)

Events

Cookie Authentication allows developers to hook into events at various lifecycle stages of authentication process. For instance, you could log successful sign-ins using OnSignedIn or use OnValidatePrincipal (runs on every request) to invalidate the user (e.g. if you want to force sign-out).

Note: For some of the events (e.g. OnValidatePrincipal), the HttpContext.User is null, use the Principal property of event’s context parameter.

Events = new CookieAuthenticationEvents
                {
                    OnSignedIn = context =>
                    {
                        Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
                          "OnSignedIn", context.Principal.Identity.Name);
                        return Task.CompletedTask;
                    },
                    OnValidatePrincipal = context =>
                    {
                        Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
                          "OnValidatePrincipal", context.Principal.Identity.Name);
                        return Task.CompletedTask;
                    },
                },

Sign Out

To delete the authentication cookie, and thus sign out the user, you call HttpContext.SignOutAsync() method with the authentication scheme name.

Cookie Expiration

In order to set an absolute expiry time for the identity/cookie (as opposed to sliding expiration), you could use AuthenticationProperties:

await HttpContext.SignInAsync(
                    scheme: "FiverSecurityScheme",
                    principal: principal,
                    properties: new AuthenticationProperties
                    {
                        ExpiresUtc = DateTime.UtcNow.AddMinutes(1)
                    });

Migrating from ASP.NET Core 1.x

Prior to ASP.NET Core 2.0, the cookie authentication was setup little differently. It was setup in Configure() method and some of the property names were different too. Below is from the project I originally created using ASP.NET Core 1.x:

app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AccessDeniedPath = new PathString("/Security/Access"),
                AuthenticationScheme = "FiverSecurityCookie",
                AutomaticAuthenticate = true,
                AutomaticChallenge = true,
                CookieHttpOnly = true,
                CookieName = ".Fiver.Security.Cookie",
                CookiePath = "/",
                CookieSecure = CookieSecurePolicy.SameAsRequest,
                Events = new CookieAuthenticationEvents
                {
                    OnSignedIn = context =>
                    {
                        Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
                          "OnSignedIn", context.Principal.Identity.Name);
                        return Task.CompletedTask;
                    },
                    OnSigningOut = context =>
                    {
                        Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
                          "OnSigningOut", context.HttpContext.User.Identity.Name);
                        return Task.CompletedTask;
                    },
                    OnValidatePrincipal = context =>
                    {
                        Console.WriteLine("{0} - {1}: {2}", DateTime.Now,
                          "OnValidatePrincipal", context.Principal.Identity.Name);
                        return Task.CompletedTask;
                    },
                },
                ExpireTimeSpan = TimeSpan.FromMinutes(5),
                LoginPath = new PathString("/Security/Login"),
                ReturnUrlParameter = "RequestPath",
                SlidingExpiration = true,
            });

Also the sign-in and sign-out methods were accessed using Authentication property on HttpContext:

await HttpContext.Authentication.SignInAsync(
                    authenticationScheme: "FiverSecurityCookie",
                    principal: principal);

            await HttpContext.Authentication.SignOutAsync(
                    authenticationScheme: "FiverSecurityCookie");

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here