Authentication is at the core of almost every modern web application. Two popular approaches are Session-based authentication and JWT-based authentication. While both achieve the goal of verifying a user’s identity, they work in different ways, each with its own strengths and trade-offs. Session-based authentication JWT-based authentication Session-Based Authentication Session-based authentication stores the user’s authentication data (usually a session ID) on the server after they log in. The client receives a cookie that contains this session ID. Every subsequent request includes this cookie, allowing the server to identify the user. How it works (Step-by-Step): User logs in → sends credentials (username/password) to server. Server verifies credentials → creates a session object in memory or database. Server generates a session ID → stores it in the session store and sends it back to the client in a cookie. Client stores the cookie → automatically sends it with each HTTP request. Server matches the session ID from the cookie to the stored session to identify the user. User logs in → sends credentials (username/password) to server. User logs in → sends credentials (username/password) to server. User logs in Server verifies credentials → creates a session object in memory or database. Server verifies credentials → creates a session object in memory or database. Server verifies credentials Server generates a session ID → stores it in the session store and sends it back to the client in a cookie. Server generates a session ID → stores it in the session store and sends it back to the client in a cookie. Server generates a session ID Client stores the cookie → automatically sends it with each HTTP request. Client stores the cookie → automatically sends it with each HTTP request. Client stores the cookie Server matches the session ID from the cookie to the stored session to identify the user. Server matches the session ID from the cookie to the stored session to identify the user. Server matches the session ID Examples by using .Net Core (Session-based) Startup.cs Configuration Startup.cs Configuration public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); app.UseRouting(); app.UseSession(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); } public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddSession(options => { options.IdleTimeout = TimeSpan.FromMinutes(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true; }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); app.UseRouting(); app.UseSession(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); } Login Controller Login Controller [HttpPost] public IActionResult Login(string username, string password) { if (username == "admin" && password == "secret") { HttpContext.Session.SetString("Username", username); return RedirectToAction("Dashboard"); } ViewBag.Error = "Invalid credentials"; return View(); } [HttpPost] public IActionResult Login(string username, string password) { if (username == "admin" && password == "secret") { HttpContext.Session.SetString("Username", username); return RedirectToAction("Dashboard"); } ViewBag.Error = "Invalid credentials"; return View(); } Protected Dashboard Protected Dashboard public IActionResult Dashboard() { var user = HttpContext.Session.GetString("Username"); if (string.IsNullOrEmpty(user)) return RedirectToAction("Login"); return View(model: $"Hello {user}"); } public IActionResult Dashboard() { var user = HttpContext.Session.GetString("Username"); if (string.IsNullOrEmpty(user)) return RedirectToAction("Login"); return View(model: $"Hello {user}"); } Pros Pros Simple to implement in MVC applications. Server-controlled session invalidation. Great for traditional web apps. Simple to implement in MVC applications. Server-controlled session invalidation. Great for traditional web apps. Cons Cons Requires server memory or distributed session store. Harder to scale without central session storage. Requires server memory or distributed session store. Requires server memory or distributed session store. Harder to scale without central session storage. Harder to scale without central session storage. JWT-Based Authentication JWT (JSON Web Token) is a compact, self-contained token containing user identity and claims. It is signed by the server and sent to the client after successful authentication. Clients send the token in the Authorization header for each request. JSON Web Token Authorization How it works (Step-by-Step): How it works (Step-by-Step): User logs in → sends credentials to server. Server validates credentials → generates a signed JWT. JWT is returned to client (usually stored in browser storage or mobile app memory). Client sends JWT in the Authorization: Bearer <token> header for each request. Server validates the token signature on each request — no session storage needed. User logs in → sends credentials to server. Server validates credentials → generates a signed JWT. JWT is returned to client (usually stored in browser storage or mobile app memory). Client sends JWT in the Authorization: Bearer <token> header for each request. Authorization: Bearer <token> Server validates the token signature on each request — no session storage needed. .NET Core Example (JWT-based) Install NuGet packages Install NuGet packages dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package System.IdentityModel.Tokens.Jwt dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package System.IdentityModel.Tokens.Jwt Startup.cs Configuration Startup.cs Configuration public void ConfigureServices(IServiceCollection services) { var key = Encoding.ASCII.GetBytes("ThisIsASecretKeyForJWT"); services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; }); services.AddControllers(); } public void ConfigureServices(IServiceCollection services) { var key = Encoding.ASCII.GetBytes("ThisIsASecretKeyForJWT"); services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false }; }); services.AddControllers(); } Login Controller (Generating JWT) Login Controller (Generating JWT) [HttpPost("login")] public IActionResult Login([FromBody] LoginModel login) { if (login.Username == "admin" && login.Password == "secret") { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes("ThisIsASecretKeyForJWT"); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, login.Username) }), Expires = DateTime.UtcNow.AddHours(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return Ok(new { Token = tokenHandler.WriteToken(token) }); } return Unauthorized(); } wt [HttpPost("login")] public IActionResult Login([FromBody] LoginModel login) { if (login.Username == "admin" && login.Password == "secret") { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes("ThisIsASecretKeyForJWT"); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, login.Username) }), Expires = DateTime.UtcNow.AddHours(1), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return Ok(new { Token = tokenHandler.WriteToken(token) }); } return Unauthorized(); } wt Protected Endpoint Protected Endpoint [Authorize] [HttpGet("dashboard")] public IActionResult Dashboard() { return Ok($"Hello {User.Identity.Name}"); } [Authorize] [HttpGet("dashboard")] public IActionResult Dashboard() { return Ok($"Hello {User.Identity.Name}"); } Pros Pros Stateless, no server-side session storage. Ideal for APIs and microservices. Works well across platforms and domains. Stateless, no server-side session storage. Ideal for APIs and microservices. Works well across platforms and domains. Cons Cons Harder to revoke tokens before expiration. Larger payload size than a session ID. Must be secured to prevent token theft. Harder to revoke tokens before expiration. Larger payload size than a session ID. Must be secured to prevent token theft. Key Differences b/w Session and JWT Feature Session-Based JWT-Based Storage Location Server-side Client-side Scalability Needs shared store Stateless, easy to scale Revocation Easy (delete session) Hard (needs blacklist) Best For Server-rendered apps APIs, mobile apps Feature Session-Based JWT-Based Storage Location Server-side Client-side Scalability Needs shared store Stateless, easy to scale Revocation Easy (delete session) Hard (needs blacklist) Best For Server-rendered apps APIs, mobile apps Feature Session-Based JWT-Based Feature Feature Session-Based Session-Based JWT-Based JWT-Based Storage Location Server-side Client-side Storage Location Storage Location Server-side Server-side Client-side Client-side Scalability Needs shared store Stateless, easy to scale Scalability Scalability Needs shared store Needs shared store Stateless, easy to scale Stateless, easy to scale Revocation Easy (delete session) Hard (needs blacklist) Revocation Revocation Easy (delete session) Easy (delete session) Hard (needs blacklist) Hard (needs blacklist) Best For Server-rendered apps APIs, mobile apps Best For Best For Server-rendered apps Server-rendered apps APIs, mobile apps APIs, mobile apps When to Use Which? When to Use Which? Use Session-based authentication when: You have a traditional server-rendered app. You want quick and simple user authentication. You control the server environment (can store sessions centrally). Use JWT-based authentication when: You’re building stateless APIs or microservices. You need scalability and no central session store. You’re serving multiple client types (web, mobile, IoT). Use Session-based authentication when: You have a traditional server-rendered app. You want quick and simple user authentication. You control the server environment (can store sessions centrally). Use Session-based authentication You have a traditional server-rendered app. You want quick and simple user authentication. You control the server environment (can store sessions centrally). You have a traditional server-rendered app. You want quick and simple user authentication. You control the server environment (can store sessions centrally). Use JWT-based authentication when: You’re building stateless APIs or microservices. You need scalability and no central session store. You’re serving multiple client types (web, mobile, IoT). Use JWT-based authentication You’re building stateless APIs or microservices. You need scalability and no central session store. You’re serving multiple client types (web, mobile, IoT). You’re building stateless APIs or microservices. You’re building stateless APIs or microservices. You need scalability and no central session store. You need scalability and no central session store. You’re serving multiple client types (web, mobile, IoT). You’re serving multiple client types (web, mobile, IoT). Example Scenario Example Scenario Session Example: A company intranet web app stores user sessions in Redis so employees can log in from different offices without losing their session. JWT Example: A mobile banking app sends a JWT to users after login. The backend API verifies the JWT for every request without storing any session, making it scalable across multiple load-balanced servers.