← Back to Article List         
Cookie Authentication in MVC

Cookie Authentication in MVC

Published on 27 Sep 2026     8 min read ASP.NET Core MVC
MVC

Cookie Authentication in ASP.NET Core MVC

Cookie authentication verifies a user and stores their authentication information in an encrypted cookie in the browser.

How it works

  1. User submits a username and password.
  2. Server validates the credentials.
  3. Server creates a ClaimsPrincipal containing the user’s identity and roles.
  4. SignInAsync() generates an encrypted authentication cookie.
  5. The browser sends this cookie with every subsequent request.
  6. Cookie Authentication Middleware validates it and sets HttpContext.User.
  7. [Authorize] allows or denies access.
await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity));
[Authorize]
public IActionResult Dashboard()
{
    return View();
}

Configuration

builder.Services.AddAuthentication("MyCookie")
    .AddCookie("MyCookie", options =>
    {
        options.LoginPath = "/Account/Login";
        options.AccessDeniedPath = "/Account/AccessDenied";
    });

app.UseAuthentication();
app.UseAuthorization();

Library: Built into ASP.NET Core through Microsoft.AspNetCore.Authentication.Cookies; normally no separate NuGet installation is required.

Interview point: The cookie stores an encrypted authentication ticket, not the user’s password.

 

How ASP.NET Core Identity Works

ASP.NET Core Identity is a membership system that manages:

  • User registration and login
  • Password hashing
  • Roles and claims
  • Email confirmation
  • Password reset
  • Two-factor authentication
  • Account lockout

Authentication flow

  1. User submits username/email and password.
  2. UserManager retrieves the user.
  3. SignInManager verifies the hashed password.
  4. Identity creates an encrypted authentication cookie.
  5. The browser sends the cookie with future requests.
  6. [Authorize] checks the authenticated user’s roles or claims.
var result = await _signInManager.PasswordSignInAsync(
    model.Email,
    model.Password,
    model.RememberMe,
    lockoutOnFailure: true);

Main components

  • UserManager – manages users, passwords, roles and claims.
  • SignInManager – handles login and logout.
  • RoleManager – manages roles.
  • IdentityDbContext – stores Identity data using EF Core.
  • PasswordHasher – securely hashes passwords.

Configuration

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

Required packages: Commonly Microsoft.AspNetCore.Identity.EntityFrameworkCore and the appropriate EF Core database provider, such as Microsoft.EntityFrameworkCore.SqlServer.

Interview point: Identity manages users and security features, while cookie authentication maintains the user’s signed-in session.

 

Authorization Types

Type Checks Example
Role-based User’s role Admin, Manager
Claims-based A user property/value Department = HR
Policy-based One or more custom requirements Admin role + age above 18

1. Role-based authorization

Allows access based on the user’s role.

[Authorize(Roles = "Admin")]
public IActionResult Dashboard() => View();

2. Claims-based authorization

Allows access based on information attached to the user’s identity.

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("HRDepartment",
        policy => policy.RequireClaim("Department", "HR"));
});
[Authorize(Policy = "HRDepartment")]

3. Policy-based authorization

Uses reusable rules that can combine roles, claims, and custom requirements.

options.AddPolicy("SeniorAdmin", policy =>
{
    policy.RequireRole("Admin");
    policy.RequireClaim("Experience", "Senior");
});
[Authorize(Policy = "SeniorAdmin")]

Key point: Role-based and claims-based authorization are simple checks. Policy-based authorization is more flexible and is preferred for complex business rules.

Library: Built into ASP.NET Core; normally no additional NuGet package is required.

 

How do you create a custom authorization policy and requirement?

Custom Authorization Policy and Requirement

A custom policy is used when authorization requires business logic that cannot be handled by a simple role or claim check.

1. Create a requirement

public class MinimumExperienceRequirement : IAuthorizationRequirement
{
    public int Years { get; }

    public MinimumExperienceRequirement(int years)
    {
        Years = years;
    }
}

2. Create a handler

public class MinimumExperienceHandler
    : AuthorizationHandler<MinimumExperienceRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        MinimumExperienceRequirement requirement)
    {
        var value = context.User.FindFirst("Experience")?.Value;

        if (int.TryParse(value, out int years) &&
            years >= requirement.Years)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

3. Register the policy and handler

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("ExperiencedEmployee", policy =>
        policy.AddRequirements(
            new MinimumExperienceRequirement(5)));
});

builder.Services.AddSingleton<
    IAuthorizationHandler,
    MinimumExperienceHandler>();

4. Apply the policy

[Authorize(Policy = "ExperiencedEmployee")]
public IActionResult Reports()
{
    return View();
}

How it works

The policy contains the requirement. The handler evaluates the logged-in user and calls context.Succeed() when the rule is satisfied.

Library: Built into ASP.NET Core using Microsoft.AspNetCore.Authorization; no additional NuGet package is normally required.

 

How do you secure controller actions and Areas?

Securing Controller Actions and Areas

Use the [Authorize] attribute to restrict access to authenticated users, roles, or policies.

Secure a controller

All actions require login:

[Authorize]
public class OrdersController : Controller
{
}

Secure a specific action

[Authorize(Roles = "Admin")]
public IActionResult Delete(int id)
{
    return View();
}

Allow public access

[AllowAnonymous] bypasses authorization:

[AllowAnonymous]
public IActionResult Login()
{
    return View();
}

Secure an Area

Apply [Authorize] to the Area’s base controller:

[Area("Admin")]
[Authorize(Roles = "Admin")]
public class AdminBaseController : Controller
{
}

Inherit other Admin controllers from it:

public class DashboardController : AdminBaseController
{
}

For stronger protection, configure an authorization convention for the entire Area:

builder.Services.AddControllersWithViews(options =>
{
    options.Conventions.Add(
        new AuthorizeAreaFolderConvention("Admin", "/"));
});

Required middleware

app.UseAuthentication();
app.UseAuthorization();

UseAuthentication() must run before UseAuthorization() and before controller endpoints are mapped.

Interview point: Secure the entire controller or Area by default, then use [AllowAnonymous] only for intentionally public actions.

Library: Authorization is built into ASP.NET Core; no additional NuGet package is normally required.

 

How do you configure external authentication providers?

External Authentication Providers

External authentication allows users to log in using providers such as Google, Microsoft, Facebook, or GitHub.

Steps

  1. Register your application with the external provider.
  2. Obtain the Client ID and Client Secret.
  3. Install the provider’s NuGet package.
  4. Configure authentication in Program.cs.
  5. Add a login button and handle the callback.

Google example

Install package:

dotnet add package Microsoft.AspNetCore.Authentication.Google

Configure:

builder.Services
    .AddAuthentication()
    .AddGoogle(options =>
    {
        options.ClientId =
            builder.Configuration["Authentication:Google:ClientId"]!;

        options.ClientSecret =
            builder.Configuration["Authentication:Google:ClientSecret"]!;
    });

Configuration:

{
  "Authentication": {
    "Google": {
      "ClientId": "your-client-id",
      "ClientSecret": "your-client-secret"
    }
  }
}

Start external login:

return Challenge(
    new AuthenticationProperties
    {
        RedirectUri = "/Account/ExternalLoginCallback"
    },
    "Google");

How it works

The user is redirected to Google → signs in → Google sends the user back to the application → the application reads the user’s claims and creates its own authentication cookie.

Security point: Store client secrets in User Secrets, environment variables, or Azure Key Vault, not directly in appsettings.json.

Interview point: The external provider verifies the user’s identity, while the MVC application manages its own local session using a cookie.

 

How do you implement logout and session expiration securely?

Secure Logout and Session Expiration

Logout

Sign out from cookie authentication and redirect to the login page:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync(
        CookieAuthenticationDefaults.AuthenticationScheme);

    return RedirectToAction("Login", "Account");
}

Use POST, not GET, and add an anti-forgery token to prevent forced logout attacks.

<form asp-action="Logout" method="post">
    <button type="submit">Logout</button>
</form>

Configure authentication expiration

builder.Services.AddAuthentication("MyCookie")
    .AddCookie("MyCookie", options =>
    {
        options.LoginPath = "/Account/Login";
        options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
        options.SlidingExpiration = true;
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Lax;
    });
  • ExpireTimeSpan – logs the user out after the configured period.
  • SlidingExpiration – renews the cookie when the active user passes halfway through the expiration period.
  • HttpOnly – prevents JavaScript from accessing the cookie.
  • Secure – sends the cookie only over HTTPS.
  • SameSite – helps protect against CSRF.

Session expiration

If MVC session storage is also used:

builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(20);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});
app.UseSession();

Interview point: Authentication-cookie expiration controls the user’s login. Session expiration controls server-side session data. They are separate.

Library: Cookie authentication and session support are built into ASP.NET Core; normally no additional NuGet package is required.

 

What is the difference between cookie authentication and JWT authentication?

Cookie Authentication vs JWT Authentication

Cookie Authentication JWT Authentication
Commonly used in MVC web applications Commonly used in Web APIs and SPAs
Token is stored in a browser cookie Token is usually sent in the Authorization header
Browser sends the cookie automatically Client must explicitly attach the token
Can be stateful or ticket-based Usually stateless
Built-in CSRF risk Less exposed to CSRF when sent through headers
Easy to revoke using server-side validation Harder to revoke before the token expires
Best for browser-based MVC applications Best for APIs, mobile apps and distributed systems

Cookie request

Cookie: MyAuthCookie=encrypted-ticket

JWT request

Authorization: Bearer eyJhbGciOi...

Important security difference

  • Cookie: Protect against CSRF using anti-forgery tokens and SameSite.
  • JWT: Protect the token from theft and XSS. Use HTTPS and short token expiration.

Interview answer

Cookie authentication is suitable for traditional MVC applications because the browser automatically manages the cookie. JWT authentication is suitable for APIs because the client sends a self-contained bearer token with each request.

Libraries:

  • Cookie authentication: Built into ASP.NET Core.
  • JWT: Usually requires Microsoft.AspNetCore.Authentication.JwtBearer.

How do you protect sensitive cookies?

Protecting Sensitive Cookies

Use the following security settings:

options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Lax;
options.Cookie.IsEssential = true;

Key protections

  • HttpOnly: Prevents JavaScript from reading the cookie, reducing cookie theft through XSS.
  • Secure: Sends the cookie only over HTTPS.
  • SameSite: Reduces CSRF attacks. Use Lax or Strict when possible.
  • Encryption and signing: ASP.NET Core Data Protection automatically protects authentication cookies.
  • Short expiration: Limits the time a stolen cookie remains usable.
  • Regenerate after login: Helps prevent session-fixation attacks.
  • Avoid sensitive data: Never store passwords, connection strings or confidential information directly in cookies.
  • Validate anti-forgery tokens: Protects state-changing form requests from CSRF.

Example

builder.Services.AddAuthentication("MyCookie")
    .AddCookie("MyCookie", options =>
    {
        options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
        options.SlidingExpiration = true;

        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Lax;
    });

Interview point: Sensitive data should normally remain on the server. Store only a protected identifier or authentication ticket in the cookie.

Library: Cookie protection uses ASP.NET Core Authentication and Data Protection; normally no additional NuGet package is required.