Section 6 of 6

Cookies and Sessions

đŸŽ¯ What You'll Learn

  • What cookies are and how they work
  • Cookie attributes (HttpOnly, Secure, SameSite)
  • How to set and read cookies in ASP.NET Core
  • What sessions are
  • Session configuration and usage
  • Cookies vs Sessions vs Tokens
  • Security best practices

What are Cookies?

Cookies are small pieces of data stored in the browser and sent with every request to the same domain.

Cookie Flow Text
1. Server sends cookie in response:
   Set-Cookie: sessionId=abc123; HttpOnly; Secure

2. Browser stores cookie

3. Browser sends cookie with every request:
   Cookie: sessionId=abc123

Common Uses

  • Session management (user login state)
  • Personalization (user preferences, theme)
  • Tracking (analytics, advertising)

Cookie Attributes

Attribute Purpose Recommended
HttpOnly Prevents JavaScript access (XSS protection) ✅ Always
Secure Only sent over HTTPS ✅ Production
SameSite CSRF protection (Strict/Lax/None) ✅ Always
Expires Expiration date Optional
Max-Age Lifetime in seconds Optional
Domain Which domains can access Optional
Path Which paths can access Optional
âš ī¸ Security Best Practices

Always use HttpOnly and Secure for sensitive cookies!

  • HttpOnly: Prevents XSS attacks
  • Secure: Prevents man-in-the-middle attacks
  • SameSite: Prevents CSRF attacks

Setting Cookies in ASP.NET Core

Basic Cookie C#
[HttpGet("set-cookie")]
public IActionResult SetCookie()
{
    // Simple cookie
    Response.Cookies.Append("username", "john_doe");
    
    return Ok("Cookie set");
}

Cookie with Options

Secure Cookie C#
[HttpPost("login")]
public IActionResult Login([FromBody] LoginDto dto)
{
    // Authenticate user...
    var sessionId = Guid.NewGuid().ToString();
    
    // Set secure cookie
    var cookieOptions = new CookieOptions
    {
        HttpOnly = true,        // Prevent JavaScript access
        Secure = true,          // HTTPS only
        SameSite = SameSiteMode.Strict, // CSRF protection
        Expires = DateTimeOffset.UtcNow.AddDays(7) // 7 days
    };
    
    Response.Cookies.Append("sessionId", sessionId, cookieOptions);
    
    return Ok(new { message = "Logged in" });
}

Reading Cookies

Read Cookie C#
[HttpGet("profile")]
public IActionResult GetProfile()
{
    // Read cookie
    if (!Request.Cookies.TryGetValue("sessionId", out var sessionId))
    {
        return Unauthorized("Not logged in");
    }
    
    // Validate session...
    return Ok(new { username = "john_doe" });
}

Deleting Cookies

Delete Cookie C#
[HttpPost("logout")]
public IActionResult Logout()
{
    // Delete cookie
    Response.Cookies.Delete("sessionId");
    
    return Ok(new { message = "Logged out" });
}

Sessions

Sessions store data on the server, identified by a session ID stored in a cookie.

Session Flow Text
1. User visits site
2. Server creates session, stores data
3. Server sends session ID as cookie
4. Browser sends session ID with requests
5. Server retrieves session data using ID

Configure Sessions

Program.cs C#
builder.Services.AddDistributedMemoryCache(); // In-memory storage
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(30); // Session timeout
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true; // GDPR compliance
});

var app = builder.Build();

app.UseSession(); // Enable sessions

Using Sessions

Session Storage C#
[HttpPost("login")]
public IActionResult Login([FromBody] LoginDto dto)
{
    // Store in session
    HttpContext.Session.SetString("username", dto.Username);
    HttpContext.Session.SetInt32("userId", 123);
    
    return Ok("Logged in");
}

[HttpGet("profile")]
public IActionResult GetProfile()
{
    // Read from session
    var username = HttpContext.Session.GetString("username");
    var userId = HttpContext.Session.GetInt32("userId");
    
    if (username == null)
        return Unauthorized("Not logged in");
    
    return Ok(new { username, userId });
}

Storing Complex Objects

Session with JSON C#
using System.Text.Json;

// Store object
var user = new { Id = 123, Name = "John", Role = "Admin" };
var json = JsonSerializer.Serialize(user);
HttpContext.Session.SetString("user", json);

// Retrieve object
var userJson = HttpContext.Session.GetString("user");
if (userJson != null)
{
    var user = JsonSerializer.Deserialize<UserDto>(userJson);
}

Cookies vs Sessions vs Tokens

Feature Cookies Sessions JWT Tokens
Storage Client (browser) Server Client (localStorage/cookie)
Size Limit ~4KB No limit ~8KB (if in cookie)
Security Medium (HttpOnly, Secure) High (server-side) Medium (signed, not encrypted)
Scalability High Low (server memory) High (stateless)
Use Case Preferences, tracking User login (traditional apps) APIs, SPAs, mobile apps
â„šī¸ Which to Use?

Cookies: User preferences, tracking
Sessions: Traditional web apps with server-side rendering
JWT Tokens: Modern APIs, SPAs, mobile apps (stateless, scalable)

Complete InvenTrack Example

Controllers/AuthController.cs C#
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly IAuthService _authService;

    public AuthController(IAuthService authService)
    {
        _authService = authService;
    }

    // Login with session
    [HttpPost("login")]
    public async Task<IActionResult> Login([FromBody] LoginDto dto)
    {
        var user = await _authService.AuthenticateAsync(dto.Username, dto.Password);
        
        if (user == null)
            return Unauthorized("Invalid credentials");
        
        // Store in session
        HttpContext.Session.SetString("username", user.Username);
        HttpContext.Session.SetInt32("userId", user.Id);
        HttpContext.Session.SetString("role", user.Role);
        
        // Set remember-me cookie (optional)
        if (dto.RememberMe)
        {
            var cookieOptions = new CookieOptions
            {
                HttpOnly = true,
                Secure = true,
                SameSite = SameSiteMode.Strict,
                Expires = DateTimeOffset.UtcNow.AddDays(30)
            };
            
            Response.Cookies.Append("rememberMe", user.Id.ToString(), cookieOptions);
        }
        
        return Ok(new { message = "Logged in successfully", user });
    }

    // Get current user
    [HttpGet("me")]
    public IActionResult GetCurrentUser()
    {
        var username = HttpContext.Session.GetString("username");
        var userId = HttpContext.Session.GetInt32("userId");
        var role = HttpContext.Session.GetString("role");
        
        if (username == null)
            return Unauthorized("Not logged in");
        
        return Ok(new { userId, username, role });
    }

    // Logout
    [HttpPost("logout")]
    public IActionResult Logout()
    {
        // Clear session
        HttpContext.Session.Clear();
        
        // Delete remember-me cookie
        Response.Cookies.Delete("rememberMe");
        
        return Ok(new { message = "Logged out successfully" });
    }

    // Set user preference (cookie)
    [HttpPost("preferences")]
    public IActionResult SetPreferences([FromBody] PreferencesDto dto)
    {
        var cookieOptions = new CookieOptions
        {
            Expires = DateTimeOffset.UtcNow.AddYears(1),
            SameSite = SameSiteMode.Lax
        };
        
        Response.Cookies.Append("theme", dto.Theme, cookieOptions);
        Response.Cookies.Append("language", dto.Language, cookieOptions);
        
        return Ok("Preferences saved");
    }
}

Security Best Practices

  • Always use HttpOnly for sensitive cookies (prevents XSS)
  • Always use Secure in production (HTTPS only)
  • Use SameSite to prevent CSRF attacks
  • Set expiration for cookies (don't keep forever)
  • Never store sensitive data in cookies (passwords, credit cards)
  • Use sessions for sensitive data (server-side storage)
  • Regenerate session IDs after login
  • Clear sessions on logout
  • Use distributed cache for sessions in production (Redis, SQL Server)
  • Consider JWT tokens for APIs (stateless, scalable)

Key Takeaways

  • Cookies: Client-side storage, sent with every request
  • Sessions: Server-side storage, identified by session ID cookie
  • HttpOnly: Prevents JavaScript access (XSS protection)
  • Secure: HTTPS only (prevents MITM attacks)
  • SameSite: CSRF protection (Strict/Lax/None)
  • Use Response.Cookies.Append() to set cookies
  • Use Request.Cookies.TryGetValue() to read cookies
  • Use HttpContext.Session for session storage
  • Cookies vs Sessions vs Tokens: Choose based on use case
  • Always follow security best practices
🎉 Part VI Complete!

Congratulations! You've completed Part VI: HTTP & Web Fundamentals. You now understand:

  • ✅ HTTP protocol basics and client-server architecture
  • ✅ Complete request/response lifecycle
  • ✅ HTTP methods (GET, POST, PUT, DELETE, PATCH)
  • ✅ HTTP status codes (2xx, 4xx, 5xx)
  • ✅ Headers and content types
  • ✅ Cookies and sessions

You now have a solid foundation in HTTP and web fundamentals! This knowledge is essential for building robust web applications and APIs. Keep up the great work! 🚀