Index: ChapterX.API/ChapterX.API.csproj
===================================================================
--- ChapterX.API/ChapterX.API.csproj	(revision 877c13c3dd0934c1d31da7988d0d2c2c5925ed55)
+++ ChapterX.API/ChapterX.API.csproj	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -8,4 +8,5 @@
 
   <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
       <PrivateAssets>all</PrivateAssets>
Index: ChapterX.API/Controllers/AuthController.cs
===================================================================
--- ChapterX.API/Controllers/AuthController.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.API/Controllers/AuthController.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,35 @@
+using ChapterX.Application.Auth;
+using MediatR;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace ChapterX.API.Controllers
+{
+    [Route("api/[controller]")]
+    [ApiController]
+    public class AuthController : ControllerBase
+    {
+        private readonly IMediator _mediator;
+
+        public AuthController(IMediator mediator)
+        {
+            _mediator = mediator;
+        }
+
+        [HttpPost("register")]
+        [AllowAnonymous]
+        public async Task<ActionResult> Register([FromBody] RegisterRequest request)
+        {
+            var response = await _mediator.Send(request);
+            return Ok(response);
+        }
+
+        [HttpPost("login")]
+        [AllowAnonymous]
+        public async Task<ActionResult> Login([FromBody] LoginRequest request)
+        {
+            var response = await _mediator.Send(request);
+            return Ok(response);
+        }
+    }
+}
Index: ChapterX.API/Program.cs
===================================================================
--- ChapterX.API/Program.cs	(revision 877c13c3dd0934c1d31da7988d0d2c2c5925ed55)
+++ ChapterX.API/Program.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -1,5 +1,8 @@
 using ChapterX.Application;
 using ChapterX.Infrastructure;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.IdentityModel.Tokens;
 using System.Reflection;
+using System.Text;
 
 var builder = WebApplication.CreateBuilder(args);
@@ -10,7 +13,44 @@
 {
     options.CustomSchemaIds(type => type.FullName);
+    options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme
+    {
+        Name = "Authorization",
+        Type = Microsoft.OpenApi.Models.SecuritySchemeType.Http,
+        Scheme = "Bearer",
+        BearerFormat = "JWT",
+        In = Microsoft.OpenApi.Models.ParameterLocation.Header,
+        Description = "Enter your JWT token"
+    });
+    options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
+    {
+        {
+            new Microsoft.OpenApi.Models.OpenApiSecurityScheme
+            {
+                Reference = new Microsoft.OpenApi.Models.OpenApiReference
+                {
+                    Type = Microsoft.OpenApi.Models.ReferenceType.SecurityScheme,
+                    Id = "Bearer"
+                }
+            },
+            Array.Empty<string>()
+        }
+    });
 });
 
-builder.Services.AddAuthentication();
+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(
+                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
+        };
+    });
 builder.Services.AddAuthorization();
 
Index: ChapterX.API/appsettings.json
===================================================================
--- ChapterX.API/appsettings.json	(revision 877c13c3dd0934c1d31da7988d0d2c2c5925ed55)
+++ ChapterX.API/appsettings.json	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -6,4 +6,9 @@
     }
   },
-  "AllowedHosts": "*"
+  "AllowedHosts": "*",
+  "Jwt": {
+    "Key": "change-this-to-a-long-secret-key-at-least-32-chars!!",
+    "Issuer": "ChapterX",
+    "Audience": "ChapterX"
+  }
 }
Index: ChapterX.Application/Auth/IJwtTokenService.cs
===================================================================
--- ChapterX.Application/Auth/IJwtTokenService.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/IJwtTokenService.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,7 @@
+namespace ChapterX.Application.Auth
+{
+    public interface IJwtTokenService
+    {
+        string GenerateToken(ChapterX.Domain.Entities.User user);
+    }
+}
Index: ChapterX.Application/Auth/LoginHandler.cs
===================================================================
--- ChapterX.Application/Auth/LoginHandler.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/LoginHandler.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,30 @@
+using ChapterX.Domain.Repositories;
+using MediatR;
+
+namespace ChapterX.Application.Auth
+{
+    public class LoginHandler : IRequestHandler<LoginRequest, LoginResponse>
+    {
+        private readonly IUserRepository _userRepository;
+        private readonly IJwtTokenService _jwtTokenService;
+
+        public LoginHandler(IUserRepository userRepository, IJwtTokenService jwtTokenService)
+        {
+            _userRepository = userRepository;
+            _jwtTokenService = jwtTokenService;
+        }
+
+        public async Task<LoginResponse> Handle(LoginRequest request, CancellationToken cancellationToken)
+        {
+            var user = await _userRepository.GetByEmailAsync(request.Email, cancellationToken)
+                ?? throw new UnauthorizedAccessException("Invalid email or password.");
+
+            if (!BCrypt.Net.BCrypt.Verify(request.Password, user.Password))
+                throw new UnauthorizedAccessException("Invalid email or password.");
+
+            var token = _jwtTokenService.GenerateToken(user);
+
+            return new LoginResponse(token, user.Id, user.Username, user.Email);
+        }
+    }
+}
Index: ChapterX.Application/Auth/LoginRequest.cs
===================================================================
--- ChapterX.Application/Auth/LoginRequest.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/LoginRequest.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,6 @@
+using MediatR;
+
+namespace ChapterX.Application.Auth
+{
+    public record LoginRequest(string Email, string Password) : IRequest<LoginResponse>;
+}
Index: ChapterX.Application/Auth/LoginResponse.cs
===================================================================
--- ChapterX.Application/Auth/LoginResponse.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/LoginResponse.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,4 @@
+namespace ChapterX.Application.Auth
+{
+    public record LoginResponse(string Token, int UserId, string Username, string Email);
+}
Index: ChapterX.Application/Auth/RegisterHandler.cs
===================================================================
--- ChapterX.Application/Auth/RegisterHandler.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/RegisterHandler.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,37 @@
+using ChapterX.Domain.Repositories;
+using MediatR;
+
+namespace ChapterX.Application.Auth
+{
+    public class RegisterHandler : IRequestHandler<RegisterRequest, RegisterResponse>
+    {
+        private readonly IUserRepository _userRepository;
+
+        public RegisterHandler(IUserRepository userRepository)
+        {
+            _userRepository = userRepository;
+        }
+
+        public async Task<RegisterResponse> Handle(RegisterRequest request, CancellationToken cancellationToken)
+        {
+            var existing = await _userRepository.GetByEmailAsync(request.Email, cancellationToken);
+            if (existing != null)
+                throw new InvalidOperationException("Email already in use.");
+
+            var user = new Domain.Entities.User
+            {
+                Username = request.Username,
+                Email = request.Email,
+                Name = request.Name,
+                Surname = request.Surname,
+                Password = BCrypt.Net.BCrypt.HashPassword(request.Password),
+                CreatedAt = DateTime.UtcNow,
+                UpdatedAt = DateTime.UtcNow
+            };
+
+            await _userRepository.AddAsync(user, cancellationToken);
+
+            return new RegisterResponse(user.Id, user.Username, user.Email);
+        }
+    }
+}
Index: ChapterX.Application/Auth/RegisterRequest.cs
===================================================================
--- ChapterX.Application/Auth/RegisterRequest.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/RegisterRequest.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,6 @@
+using MediatR;
+
+namespace ChapterX.Application.Auth
+{
+    public record RegisterRequest(string Username, string Email, string Name, string Surname, string Password) : IRequest<RegisterResponse>;
+}
Index: ChapterX.Application/Auth/RegisterResponse.cs
===================================================================
--- ChapterX.Application/Auth/RegisterResponse.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Application/Auth/RegisterResponse.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,4 @@
+namespace ChapterX.Application.Auth
+{
+    public record RegisterResponse(int UserId, string Username, string Email);
+}
Index: ChapterX.Application/ChapterX.Application.csproj
===================================================================
--- ChapterX.Application/ChapterX.Application.csproj	(revision 877c13c3dd0934c1d31da7988d0d2c2c5925ed55)
+++ ChapterX.Application/ChapterX.Application.csproj	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -8,4 +8,5 @@
 
   <ItemGroup>
+    <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
     <PackageReference Include="MediatR" Version="14.1.0" />
     <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
Index: ChapterX.Infrastructure/ChapterX.Infrastructure.csproj
===================================================================
--- ChapterX.Infrastructure/ChapterX.Infrastructure.csproj	(revision 877c13c3dd0934c1d31da7988d0d2c2c5925ed55)
+++ ChapterX.Infrastructure/ChapterX.Infrastructure.csproj	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -8,4 +8,5 @@
 
   <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.0" />
     <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.0">
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Index: ChapterX.Infrastructure/DependencyInjection.cs
===================================================================
--- ChapterX.Infrastructure/DependencyInjection.cs	(revision 877c13c3dd0934c1d31da7988d0d2c2c5925ed55)
+++ ChapterX.Infrastructure/DependencyInjection.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -1,6 +1,8 @@
 using ChapterX.Application.Abstractions;
+using ChapterX.Application.Auth;
 using ChapterX.Domain.Repositories;
 using ChapterX.Infrastructure.Data.DataContext;
 using ChapterX.Infrastructure.Repositories;
+using ChapterX.Infrastructure.Services;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Configuration;
@@ -17,4 +19,5 @@
 
             services.AddScoped<IApplicationDbContext>(sp => sp.GetRequiredService<ApplicationDbContext>());
+            services.AddScoped<IJwtTokenService, JwtTokenService>();
 
             services.AddScoped<IUserRepository, UserRepository>();
Index: ChapterX.Infrastructure/Services/JwtTokenService.cs
===================================================================
--- ChapterX.Infrastructure/Services/JwtTokenService.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
+++ ChapterX.Infrastructure/Services/JwtTokenService.cs	(revision e294f7d2cedd462a923c69ae9f85c996b5377c69)
@@ -0,0 +1,44 @@
+using ChapterX.Application.Auth;
+using ChapterX.Domain.Entities;
+using Microsoft.Extensions.Configuration;
+using Microsoft.IdentityModel.Tokens;
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+
+namespace ChapterX.Infrastructure.Services
+{
+    public class JwtTokenService : IJwtTokenService
+    {
+        private readonly IConfiguration _configuration;
+
+        public JwtTokenService(IConfiguration configuration)
+        {
+            _configuration = configuration;
+        }
+
+        public string GenerateToken(User user)
+        {
+            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]!));
+            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
+
+            var claims = new[]
+            {
+                new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
+                new Claim(JwtRegisteredClaimNames.Email, user.Email),
+                new Claim(JwtRegisteredClaimNames.UniqueName, user.Username),
+                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
+            };
+
+            var token = new JwtSecurityToken(
+                issuer: _configuration["Jwt:Issuer"],
+                audience: _configuration["Jwt:Audience"],
+                claims: claims,
+                expires: DateTime.UtcNow.AddDays(7),
+                signingCredentials: credentials
+            );
+
+            return new JwtSecurityTokenHandler().WriteToken(token);
+        }
+    }
+}
