INTRODUCTION/ ISSUE 

In today’s web development landscape, authentication isn’t just about allowing users to log in — it’s about securing their data, keeping them logged in efficiently, and ensuring smooth user experience. Whether you’re building a small application or an enterprise-grade system, the way you authenticate users can make or break your application’s trustworthiness. 

One of the most popular and efficient solutions for modern authentication is JWT (JSON Web Token). When combined with .NET Core for the backend and React for the frontend, JWT becomes a powerful tool to create a secure, fast, and scalable login system. 

In this blog, we’ll walk through why JWT is the preferred choice, how to set up your project, and step-by-step implementation of a JWT-based authentication system. 

 

WHY DO WE NEED TO DO/ CAUSE OF THE ISSUE 

  • Before jumping into the how, let’s understand the why: 
  • Stateless Authentication
    Unlike traditional session-based authentication, JWT doesn’t require storing session data on the server. The server simply verifies the token — making the system scalable and less memory-intensive. 
  • Cross-Platform Compatibility
    JWTs are JSON objects, which means they work seamlessly across different platforms and languages — ideal for .NET Core + React setups. 
  • Better Performance
    Since authentication data is embedded in the token itself, the server doesn’t have to repeatedly query the database for each request. 
  • Secure Data Transmission
    JWTs are signed (and optionally encrypted), ensuring that data isn’t tampered with during transmission. 
  • Industry Standard
    JWT has become the go-to authentication mechanism for REST APIs — meaning developers can rely on a well-tested, widely adopted approach. 

 

How to set up the project: 

Before we begin, make sure you have: 

  • .NET Core SDK (6.0 or above) installed 
  • Node.js & npm installed 
  • Visual Studio or VS Code 
  • SQL Server (or any preferred database) 
  • Basic knowledge of C#, .NET Core, and React 

 

HOW DO WE SOLVE 

We’ll break down the solution into two parts: 

  1. Backend (.NET Core API) – Handles authentication, JWT generation, and protected routes. 
  1. Frontend (React) – Handles login UI, token storage, and API calls with JWT. 

Backend – .NET Core API 

Step 1: Create a .NET Core Web API Project 

dotnet new webapi -n JwtAuthDemo 

cd JwtAuthDemo 

Step 2: Install Required NuGet Packages 

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer 

dotnet add package System.IdentityModel.Tokens.Jwt 

Step 3: Configure JWT in appsettings.json  

“jwt”:{ 

   “Key”: “ThisIsASecretKeyForJwtTokenDontShare”, 

      “Issuer”: https://yourdomain.com, 

      “Audience”: https://yourdomain.com, 

      “ExpiryMinutes”: 60 

} 

Step 4: Add JWT Authentication in Program.cs 

using Microsoft.AspNetCore.Authentication.JwtBearer; 

using Microsoft.IdentityModel.Tokens; 

using System.Text;  

var builder = WebApplication.CreateBuilder(args); 

var key = Encoding.UTF8.GetBytes(builder.Configuration[“Jwt:Key”]); 

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) 

    .AddJwtBearer(options => 

    { 

        options.TokenValidationParameters = new TokenValidationParameters 

        { 

            ValidateIssuer = true, 

            ValidateAudience = true, 

            ValidateLifetime = true, 

            ValidateIssuerSigningKey = true, 

            ValidIssuer = builder.Configuration[“Jwt:Issuer”], 

            ValidAudience = builder.Configuration[“Jwt:Audience”], 

            IssuerSigningKey = new SymmetricSecurityKey(key) 

        }; 

    }); 

builder.Services.AddControllers(); 

var app = builder.Build(); 

app.UseAuthentication(); 

app.UseAuthorization(); 

app.MapControllers(); 

app.Run(); 

 

Step 5: Create a Login Endpoint (AuthController.cs) 

[ApiController] 

[Route(“api/[controller]”)] 

public class AuthController : ControllerBase 

{ 

    private readonly IConfiguration _config; 

    public AuthController(IConfiguration config) 

    { 

        _config = config; 

    } 

    [HttpPost(“login”)] 

    public IActionResult Login([FromBody] UserLogin login) 

    { 

        if (login.Username == “admin” && login.Password == “password”) 

        { 

            var token = GenerateJwtToken(login.Username); 

            return Ok(new { Token = token }); 

        } 

        return Unauthorized(); 

    }  

    private string GenerateJwtToken(string username) 

    { 

        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config[“Jwt:Key”])); 

        var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); 

        var token = new JwtSecurityToken( 

            _config[“Jwt:Issuer”], 

            _config[“Jwt:Audience”], 

            expires: DateTime.Now.AddMinutes(Convert.ToDouble(_config[“Jwt:ExpiryMinutes”])), 

            signingCredentials: credentials 

        ); 

        return new JwtSecurityTokenHandler().WriteToken(token); 

    } 

} 

public class UserLogin 

{ 

    public string Username { get; set; } 

    public string Password { get; set; } 

} 

  

Frontend – React 

Step 1: Create a React App 

Update reusable-card.component.html: 

npx create-react-app jwt-auth-frontend 

cd jwt-auth-frontend 

npm install axios 

Step 2: Create a Login Form (Login.js) 

Import it directly into any module or component without declaring it in NgModules: 

import { useState } from “react”; 

import axios from “axios”; 

function Login() { 

  const [username, setUsername] = useState(“”); 

  const [password, setPassword] = useState(“”); 

  const handleLogin = async () => { 

    try { 

      const res = await axios.post(“https://localhost:5001/api/auth/login”, { 

        username, 

        password, 

      }); 

      localStorage.setItem(“token”, res.data.token); 

      alert(“Login Successful”); 

    } catch { 

      alert(“Invalid Credentials”); 

    } 

  }; 

  return ( 

    <div> 

      <h2>Login</h2> 

      <input placeholder=”Username” onChange={e => setUsername(e.target.value)} /> 

      <input type=”password” placeholder=”Password” onChange={e => setPassword(e.target.value)} /> 

      <button onClick={handleLogin}>Login</button> 

    </div> 

  ); 

} 

export default Login;  

Step 3: Call Protected API with Token (Dashboard.js) 

import axios from “axios”; 

import { useEffect, useState } from “react”; 

function Dashboard() { 

  const [data, setData] = useState(“”); 

  useEffect(() => { 

    const token = localStorage.getItem(“token”); 

    axios.get(“https://localhost:5001/api/protected”, { 

      headers: { Authorization: `Bearer ${token}` } 

    }).then(res => setData(res.data)) 

      .catch(() => setData(“Unauthorized”)); 

  }, []); 

  return <div>{data}</div>; 

} 

export default Dashboard; 

 

CONCLUSION 

JWT authentication with .NET Core and React offers a clean, scalable, and secure way to handle user authentication. By keeping the backend stateless, we simplify server-side management and  

scalability. 

With this setup, you now have a fully functional JWT login system where: 

  • The backend issues a token after verifying credentials. 
  • The frontend stores the token and sends it with each request. 
  • Protected routes are accessible only to authenticated users. 

This approach is production-ready with minor enhancements such as token refresh, role-based access, and secure cookie storage. 

Recent Posts

Start typing and press Enter to search