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.
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 |
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
[HttpGet("set-cookie")]
public IActionResult SetCookie()
{
// Simple cookie
Response.Cookies.Append("username", "john_doe");
return Ok("Cookie set");
}
Cookie with Options
[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
[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
[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.
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
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
[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
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 |
Cookies: User preferences, tracking
Sessions: Traditional web apps with server-side rendering
JWT Tokens: Modern APIs, SPAs, mobile apps (stateless, scalable)
Complete InvenTrack Example
[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.Sessionfor session storage - Cookies vs Sessions vs Tokens: Choose based on use case
- Always follow security best practices
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! đ