Cookie Authentication In ASP.NET Core

In this article, we will learn how to implement Cookie Authentication in ASP.NET Core without using Identity. I will try to cover every step so that beginners can easily understand.
 
This article is the part of ASP.NET Core learning series. If you are new to ASP.NET Core, then I will recommend you to go through the previous articles of this series,
Authentication is the process of verifying the identity of the user. In this article, we will authenticate the user by verifying the user’s credentials. I am using Visual Studio 2019 to demonstrate this example. 
 

Let’s implement the Cookie Authentication in ASP.NET Core step by step

 
Open the Visual Studio and click on Create a new Project.
 
Cookie Authentication In ASP.NET Core
 
Select ASP.NET Core Empty project and click on next.
 
Cookie Authentication In ASP.NET Core
 
Give a name to your Project, select the location for the project creation, and click on Next.
 
Cookie Authentication In ASP.NET Core
 
Select the Target Framework. I am using .Net Core 3.1 (LTS) and click on create.
 
Cookie Authentication In ASP.NET Core
 
A similar kind of project as shown in the below image will be created.
 
Cookie Authentication In ASP.NET Core
 
As we have created an empty project, let's open the Startup.cs file and add the highlighted code. In the ConfigureServices method, I have added the AddControllersWithViews service and added the UseEndpoints middleware in Configure method as shown in the below image.
 
Cookie Authentication In ASP.NET Core
 
Add a Controllers folder in the project in which we will create all the controllers.
 
Cookie Authentication In ASP.NET Core
 
Let’s add a HomeController by right-clicking on the Controller folder. Go to Add and click on Controller. Select the empty controller as shown in the below image.
 
Cookie Authentication In ASP.NET Core
 
Cookie Authentication In ASP.NET Core
 
Right-click on the project and click on manage NuGet Packages. Browse Bootstrap (only required for the UI Style) and click on Install.

Cookie Authentication In ASP.NET Core
 
In order to serve the static files like js, CSS, images, etc., we need to UseStaticFiles middleware in Configure method.
 
Cookie Authentication In ASP.NET Core
 
I have added to Action methods in HomeController i.e., Index and ConfidentialData.
 
Cookie Authentication In ASP.NET Core
 
So, on clicking on the Home and confidential Data link in the navigation the below screen will be shown.
 
Cookie Authentication In ASP.NET Core
Cookie Authentication In ASP.NET Core
Another controller i.e., AccountController with a Login page as shown in the below image.
 
Cookie Authentication In ASP.NET Core
 
In ConfigureServices method of Startup.cs, create an Authentication Middleware Services with the AddAuthentication and AddCookie method. Authentication scheme passed to AddAuthentication sets to the default authentication scheme for the app. CookieAuthenticationDefaults.AuthenticationScheme provides “Cookies” for the scheme. In AddCookie extension method, set the LoginPath property of CookieAuthenticationOptions to “/account/login”. CookieAuthenticationOptions class is used to configure the authentication provider options.
 
Cookie Authentication In ASP.NET Core
 
In Configure method of Startup.cs, call UseAuthentication and UseAuthorization method before calling the endpoints.
 
Cookie Authentication In ASP.NET Core
 
Now let’s add the Authorize attribute, on ConfidentialData action method. Now only authenticate methods can access that ActionMethod.
 
Cookie Authentication In ASP.NET Core
 
Let’s click on Confidential Data link in the navbar. It will redirect to “Account/Login” page as the user is not authenticated yet.
 
Cookie Authentication In ASP.NET Core
 
In AccountController, the Login action method receives the return URL as a parameter to which the user needs to be redirected after the successful authentication. Below is the Login.cshtml code used in the example.
  1. @model CookieAuthentication.Models.LoginModel    
  2. @{    
  3.     ViewData["Title"] = "Login";    
  4.     Layout = "~/Views/Shared/_Layout.cshtml";    
  5. }    
  6. <h2>Login</h2>    
  7. <hr />    
  8. <div class="row">    
  9.     <div class="col-md-4">    
  10.         <form asp-action="Login">    
  11.             <div asp-validation-summary="ModelOnly" class="text-danger"></div>    
  12.             @if (!string.IsNullOrEmpty(ViewBag.Message))    
  13.             {    
  14.                 <span class="text-danger">    
  15.                     @ViewBag.Message    
  16.                 </span>    
  17.             }    
  18.             @Html.HiddenFor(x => x.ReturnUrl)    
  19.             <div class="form-group">    
  20.                 <label asp-for="UserName" class="control-label"></label>    
  21.                 <input asp-for="UserName" class="form-control" />    
  22.                 <span asp-validation-for="UserName" class="text-danger"></span>    
  23.             </div>    
  24.             <div class="form-group">    
  25.                 <label asp-for="Password" class="control-label"></label>    
  26.                 <input asp-for="Password" class="form-control" />    
  27.                 <span asp-validation-for="Password" class="text-danger"></span>    
  28.             </div>    
  29.             <div class="form-group">    
  30.                 <div class="checkbox">    
  31.                     <label>    
  32.                         <input asp-for="RememberLogin" /> @Html.DisplayNameFor(model => model.RememberLogin)    
  33.                     </label>    
  34.                 </div>    
  35.             </div>    
  36.             <div class="form-group">    
  37.                 <input type="submit" value="Login" class="btn btn-default" />    
  38.             </div>    
  39.         </form>    
  40.     </div>    
  41. </div>     
LoginModel.cs file
  1. public class LoginModel {  
  2.     [Required]  
  3.     [Display(Name = "Username")]  
  4.     public string UserName {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     [Required]  
  9.     [DataType(DataType.Password)]  
  10.     public string Password {  
  11.         get;  
  12.         set;  
  13.     }  
  14.     public bool RememberLogin {  
  15.         get;  
  16.         set;  
  17.     }  
  18.     public string ReturnUrl {  
  19.         get;  
  20.         set;  
  21.     }  
  22. }   
On clicking on the login button, the Login Post action will be triggered. In Post action, we are verifying the username and password (In this example, I am using the hardcoded user details, but in actuality you can verify the user details with an ORM like EntityFramework, Dapper, etc.) If entered credentials are not valid then an Invalid credential message will be shown to the user. If credentials are correct create a ClaimsIdentity with the required Claims. Call the SignInAsync to sign in the user.
  1. public class AccountController: Controller {  
  2.     //Sample Users Data, it can be fetched with the use of any ORM    
  3.     public List < UserModel > users = null;  
  4.     public AccountController() {  
  5.         users = new List < UserModel > ();  
  6.         users.Add(new UserModel() {  
  7.             UserId = 1, Username = "Anoop", Password = "123", Role = "Admin"  
  8.         });  
  9.         users.Add(new UserModel() {  
  10.             UserId = 2, Username = "Other", Password = "123", Role = "User"  
  11.         });  
  12.     }  
  13.     public IActionResult Login(string ReturnUrl = "/") {  
  14.             LoginModel objLoginModel = new LoginModel();  
  15.             objLoginModel.ReturnUrl = ReturnUrl;  
  16.             return View(objLoginModel);  
  17.         }  
  18.         [HttpPost]  
  19.     public async Task < IActionResult > Login(LoginModel objLoginModel) {  
  20.         if (ModelState.IsValid) {  
  21.             var user = users.Where(x => x.Username == objLoginModel.UserName && x.Password == objLoginModel.Password).FirstOrDefault();  
  22.             if (user == null) {  
  23.                 //Add logic here to display some message to user    
  24.                 ViewBag.Message = "Invalid Credential";  
  25.                 return View(objLoginModel);  
  26.             } else {  
  27.                 //A claim is a statement about a subject by an issuer and    
  28.                 //represent attributes of the subject that are useful in the context of authentication and authorization operations.    
  29.                 var claims = new List < Claim > () {  
  30.                     new Claim(ClaimTypes.NameIdentifier, Convert.ToString(user.UserId)),  
  31.                         new Claim(ClaimTypes.Name, user.Username),  
  32.                         new Claim(ClaimTypes.Role, user.Role),  
  33.                         new Claim("FavoriteDrink""Tea")  
  34.                 };  
  35.                 //Initialize a new instance of the ClaimsIdentity with the claims and authentication scheme    
  36.                 var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);  
  37.                 //Initialize a new instance of the ClaimsPrincipal with ClaimsIdentity    
  38.                 var principal = new ClaimsPrincipal(identity);  
  39.                 //SignInAsync is a Extension method for Sign in a principal for the specified scheme.    
  40.                 await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties() {  
  41.                     IsPersistent = objLoginModel.RememberLogin  
  42.                 });  
  43.                 return LocalRedirect(objLoginModel.ReturnUrl);  
  44.             }  
  45.         }  
  46.         return View(objLoginModel);  
  47.     }  
  48.     public async Task < IActionResult > LogOut() {  
  49.         //SignOutAsync is Extension method for SignOut    
  50.         await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);  
  51.         //Redirect to home page    
  52.         return LocalRedirect("/");  
  53.     }  
  54. }   
Once the user is successfully logged in to the application, a cookie will be generated as shown in the below image. This encrypted cookie will be sent to the server in each request and validated on the server with its key.
 
Cookie Authentication In ASP.NET Core
 
In order to show the Claims information on Confidential Data view, code, as shown in the below image, is used. In the below code, we are checking that the user must be Authenticated before looping through each Claim.
 
Cookie Authentication In ASP.NET Core
 
Cookie Authentication In ASP.NET Core
 
Logout link is shown to the user who is already signed in. On Clicking on the Logout link, we are calling the SignOutAsync method which signs out the user and deletes their cookie.
  1. public async Task < IActionResult > LogOut() {  
  2.     //SignOutAsync is Extension method for SignOut    
  3.     await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);  
  4.     //Redirect to home page    
  5.     return LocalRedirect("/");  
  6. }   
Final Preview
 
Cookie Authentication In ASP.NET Core
 
I hope this article helped you in implementing Cookie Authentication in ASP.
 
Thanks. You can also get the code through the GitHub.