ASP.NET Core  

Using Angular + ASP.NET Core Web API Login & JWT Authentication

A Full Step-by-Step Tutorial for Beginners
Using Angular + ASP.NET Core Web API

Modern web applications require secure authentication. One of the most common and effective methods is JWT authentication. JWT stands for JSON Web Token, and it is widely used in single-page applications such as Angular, React, and Vue because it works very well with APIs.

In this tutorial, you will learn everything you need to build a full login system with JWT authentication using:

  • Angular (frontend)

  • ASP.NET Core Web API (backend)

  • JWT token generation and validation

  • SQL Server (optional but recommended)

This guide explains each step in simple language so even beginners can follow.

What You Will Build

By the end of this tutorial, you will have:

  1. A login form in Angular

  2. A .NET API endpoint that verifies users

  3. A JWT token generated by the API

  4. Angular storing the token in localStorage

  5. Angular automatically attaching the token on protected requests

  6. A protected API endpoint that only logged-in users can access

  7. Token validation and token expiration handling

This is the foundation of any real-world authentication system.

What Is JWT

JWT means JSON Web Token.
It is a small, signed text string that stores user information.

Example JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

A JWT contains three parts:

  1. Header

  2. Payload (user data)

  3. Signature (to verify token authenticity)

Once a user logs in:

  • API gives JWT to Angular

  • Angular stores it

  • Angular sends it in the Authorization header for protected API calls

  • API verifies the token before allowing access

JWT is stateless. The server does not store any session information.

Part 1: Backend – ASP.NET Core API with JWT

Step 1: Create a Web API Project

dotnet new webapi -n JwtAuthAPI

Step 2: Add JWT NuGet Package

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

Step 3: Create User Model

In Models/User.cs:

public class User
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

This is a simple example.
For real systems: hash passwords and use ASP.NET Identity.

Step 4: Configure JWT in appsettings.json

"Jwt": {
  "Key": "ThisIsASecretKeyForJwtToken12345",
  "Issuer": "JwtAuthAPI",
  "Audience": "JwtAuthAPIUser"
}

The key must be long and secure.

Step 5: Configure JWT Authentication in Program.cs

Add:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

Then configure:

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)
    };
});

Add middleware:

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

Step 6: Create Token Generator Service

Create Services/JwtService.cs:

public class JwtService
{
    private readonly IConfiguration _config;

    public JwtService(IConfiguration config)
    {
        _config = config;
    }

    public string GenerateToken(string email)
    {
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var claims = new[]
        {
            new Claim(ClaimTypes.Email, email)
        };

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.Now.AddHours(1),
            signingCredentials: creds);

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Register it in Program.cs:

builder.Services.AddScoped<JwtService>();

Step 7: Create Login Endpoint

In Controllers/AuthController.cs:

[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    private readonly JwtService _jwt;

    public AuthController(JwtService jwt)
    {
        _jwt = jwt;
    }

    [HttpPost("login")]
    public IActionResult Login(User user)
    {
        // Dummy example, replace with database lookup
        if (user.Email == "[email protected]" && user.Password == "123456")
        {
            var token = _jwt.GenerateToken(user.Email);
            return Ok(new { Token = token });
        }

        return Unauthorized(new { Message = "Invalid credentials" });
    }
}

Your backend is ready.

Step 8: Create Protected API Endpoint

[Authorize]
[HttpGet("profile")]
public IActionResult Profile()
{
    return Ok(new { Message = "This is protected data" });
}

This endpoint requires a valid JWT.

Part 2: Frontend – Angular Authentication

Step 1: Create Angular Project

ng new jwt-auth-app
cd jwt-auth-app

Step 2: Enable HttpClientModule

In app.module.ts:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [BrowserModule, HttpClientModule],
})
export class AppModule {}

Step 3: Create Login Form Component

ng generate component login

Step 4: Build Login Form

In login.component.html:

<h2>Login</h2>

<form (ngSubmit)="login()">

  <label>Email</label>
  <input type="email" [(ngModel)]="user.email" name="email" required>

  <label>Password</label>
  <input type="password" [(ngModel)]="user.password" name="password" required>

  <button type="submit">Login</button>

</form>

<p>{{ message }}</p>

Step 5: Angular AuthService

ng generate service auth

In auth.service.ts:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  private url = "https://localhost:5001/api/auth/login";

  constructor(private http: HttpClient) {}

  login(user: any) {
    return this.http.post<any>(this.url, user);
  }

  saveToken(token: string) {
    localStorage.setItem('token', token);
  }

  getToken() {
    return localStorage.getItem('token');
  }

  isLoggedIn() {
    return !!localStorage.getItem('token');
  }
}

Step 6: Implement Login Method

In login.component.ts:

import { Component } from '@angular/core';
import { AuthService } from '../auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html'
})
export class LoginComponent {

  message = "";

  user = {
    email: "",
    password: ""
  };

  constructor(private authService: AuthService) {}

  login() {
    this.authService.login(this.user).subscribe({
      next: (res) => {
        this.authService.saveToken(res.token);
        this.message = "Login successful";
      },
      error: () => {
        this.message = "Invalid email or password";
      }
    });
  }
}

Part 3: Protect API Calls From Angular

Step 1: Create Auth Interceptor

ng generate interceptor auth

In auth.interceptor.ts:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler } from '@angular/common/http';
import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private auth: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {

    const token = this.auth.getToken();

    if (token) {
      req = req.clone({
        setHeaders: { Authorization: `Bearer ${token}` }
      });
    }

    return next.handle(req);
  }
}

Enable it in app.module.ts:

providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true
  }
]

Now Angular automatically attaches JWT in requests.

Part 4: Call Protected API

In your Angular component:

getProfile() {
  this.http.get("https://localhost:5001/api/auth/profile")
    .subscribe(res => console.log(res));
}

If the user is logged in, this works.
If not, API returns 401 Unauthorized.

Part 5: Summary of System Flow

  1. User enters email and password in Angular

  2. Angular sends credentials to ASP.NET Core

  3. API validates user

  4. API returns JWT token

  5. Angular saves token in localStorage

  6. Angular adds token to Authorization header

  7. API validates token on protected endpoints

  8. If valid, data is returned

  9. If invalid or expired, 401 Unauthorized is returned

This is the complete JWT authentication cycle.