Skip to main content

Cookie Authentication

Overview

Cookie-based authentication stores session information in encrypted cookies. The server validates the cookie on each request. Unlike JWT, cookies are stateful and managed by the server.

Implementation

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.Name = "MyApp.Auth";
options.LoginPath = "/login";
options.LogoutPath = "/logout";
options.AccessDeniedPath = "/access-denied";
options.ExpireTimeSpan = TimeSpan.FromHours(1);
options.SlidingExpiration = true;
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});

builder.Services.AddAuthorization();

var app = builder.Build();

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

2. Login Implementation

app.MapPost("/api/auth/login", async (LoginRequest request, HttpContext context) =>
{
// Validate credentials
if (request.Email == "user@example.com" && request.Password == "password")
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, request.Email),
new Claim(ClaimTypes.Email, request.Email),
new Claim(ClaimTypes.Role, "User")
};

var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.AddHours(1)
};

await context.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);

return Results.Ok(new { message = "Login successful" });
}

return Results.Unauthorized();
});

3. Logout Implementation

app.MapPost("/api/auth/logout", async (HttpContext context) =>
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Results.Ok(new { message = "Logged out successfully" });
});

4. Get Current User

app.MapGet("/api/auth/user", (HttpContext context) =>
{
var user = context.User;

if (!user.Identity.IsAuthenticated)
return Results.Unauthorized();

return Results.Ok(new
{
email = user.FindFirst(ClaimTypes.Email)?.Value,
name = user.FindFirst(ClaimTypes.Name)?.Value,
role = user.FindFirst(ClaimTypes.Role)?.Value
});
}).RequireAuthorization();
AspectCookiesJWT
StateStateful (server session)Stateless
StorageServer-sideClient-side
ScalabilityRequires session storeHighly scalable
SecurityHttpOnly, Secure, SameSiteSignature verification
Use CaseTraditional web appsAPIs, mobile apps
CSRFVulnerable (needs protection)Not vulnerable
SizeSmall cookieLarger token

Best Practices

  1. Always use HTTPS in production
  2. Set HttpOnly to prevent JavaScript access
  3. Use Secure flag for HTTPS-only cookies
  4. Set SameSite to prevent CSRF
  5. Implement sliding expiration for better UX
  6. Use anti-forgery tokens for state-changing operations

Resources