I'm having trouble with my application. Even though the user check is completed successfully, no cookies are being added to the browser. I have tried with many users and browsers but I couldn't get any results. Please help me with this issue, thank you.Communication Flow:
login.razor:Captures user login credentials and sends a request to AuthController via AuthService.AuthService.cs:Forwards the user credentials received from the login.razor component to AuthController.Receives the token information from AuthController and checks the cookie added to the browser.AuthController.cs:Verifies the user's credentials using SignInManager.Once the user is authenticated, generates a JWT token using TokenService.Stores the generated token as a cookie using CookieService.Returns the token along with an OK response to AuthService.TokenService.cs:Invoked by AuthController to generate a JWT token.After creating the token, it returns it to AuthController.CookieService.cs:Invoked by AuthController to store the generated token as a cookie.Logs any errors during the cookie operations via ILogger.
Login.razor
@page "/login"@using System.Net.Http.Headers@inject AuthService AuthService@inject NavigationManager NavigationManager<EditForm Model="@loginModel" OnValidSubmit="HandleLogin"><DataAnnotationsValidator /><ValidationSummary /><InputText @bind-Value="loginModel.UserName" /><InputText @bind-Value="loginModel.Password" type="password" /><div class="text-danger">@errorMessage</div><button type="submit">Login</button></EditForm>@code { private LoginViewModel loginModel = new LoginViewModel(); private string errorMessage = string.Empty; private async Task HandleLogin() { var response = await AuthService.Login(loginModel); if (response.IsSuccessStatusCode) { var token = AuthService.GetAuthToken(); if (!string.IsNullOrEmpty(token)) { var client = AuthService.GetHttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); } NavigationManager.NavigateTo("/"); Console.WriteLine(token); } else { errorMessage = await response.Content.ReadAsStringAsync(); } }}AuthService.cs
public class AuthService{ private readonly HttpClient _httpClient; private readonly HttpClientHandler _httpClientHandler; private readonly ILogger<AuthService> _logger; public AuthService(HttpClient httpClient, ILogger<AuthService> logger) { _httpClientHandler = new HttpClientHandler { UseCookies = true, CookieContainer = new CookieContainer() }; _httpClient = new HttpClient(_httpClientHandler); _logger = logger; if (_httpClient.BaseAddress == null) { _httpClient.BaseAddress = new Uri("https://localhost:7025/"); } } public async Task<HttpResponseMessage> Login(LoginViewModel model) { try { _logger.LogInformation("Login isteği gönderiliyor."); var response = await _httpClient.PostAsJsonAsync("api/auth/login", model); if (response.IsSuccessStatusCode) { _logger.LogInformation("Login succes."); } else { _logger.LogWarning("Login error. Durum kodu: {StatusCode}", response.StatusCode); } return response; } catch (Exception ex) { _logger.LogError(ex, "An error occurred during the login request."); throw; } } public string GetAuthToken() { try { var cookies = _httpClientHandler.CookieContainer.GetCookies(_httpClient.BaseAddress); var authToken = cookies["authToken"]?.Value; if (authToken != null) { _logger.LogInformation("authToken cookie received: {Token}", authToken); } else { _logger.LogWarning("authToken cookie not found."); } return authToken; } catch (Exception ex) { _logger.LogError(ex, "An error occurred while retrieving the authToken cookie."); throw; } } public HttpClient GetHttpClient() { return _httpClient; }}CookieService.cs
public class CookieService{ private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger<CookieService> _logger; public CookieService(IHttpContextAccessor httpContextAccessor, ILogger<CookieService> logger) { _httpContextAccessor = httpContextAccessor; _logger = logger; } public void SetAuthTokenCookie(string token) { var cookieOptions = new CookieOptions { Expires = DateTime.Now.AddDays(30), HttpOnly = true, Secure = true, SameSite = SameSiteMode.Lax, IsEssential = true }; _httpContextAccessor.HttpContext.Response.Cookies.Append("authToken", token, cookieOptions); _logger.LogInformation("The authToken cookie was added successfully."); } public string GetAuthTokenCookie() { var token = _httpContextAccessor.HttpContext.Request.Cookies["authToken"]; if (token == null) { _logger.LogWarning("The authToken cookie was not found."); } else { _logger.LogInformation("authToken cookie received: {Token}", token); } return token; } public void RemoveAuthTokenCookie() { _httpContextAccessor.HttpContext.Response.Cookies.Delete("authToken"); _logger.LogInformation("The authToken cookie was deleted."); }}AuthController.cs
[ApiController][Route("api/[controller]")]public class AuthController : ControllerBase{ private readonly SignInManager<ApplicationUser> _signInManager; private readonly TokenService _tokenService; private readonly CookieService _cookieService; private readonly ILogger<AuthController> _logger; public AuthController(SignInManager<ApplicationUser> signInManager, TokenService tokenService, CookieService cookieService, ILogger<AuthController> logger) { _signInManager = signInManager; _tokenService = tokenService; _cookieService = cookieService; _logger = logger; } [HttpPost("login")] public async Task<IActionResult> Login([FromBody] LoginViewModel model) { try { var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false); if (result.Succeeded) { var token = _tokenService.GenerateToken(model.UserName); _cookieService.SetAuthTokenCookie(token); return Ok(new { token }); } else { _logger.LogWarning("Invalid login attempt for user: {UserName}", model.UserName); return Unauthorized("Invalid login attempt."); } } catch (Exception ex) { _logger.LogError(ex, "An error occurred during the login process."); return StatusCode(500, "Internal server error"); } }}TokenService.cs
private readonly IConfiguration _configuration;public TokenService(IConfiguration configuration){ _configuration = configuration;}public string GenerateToken(string userName){ var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, userName), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"])); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _configuration["Jwt:Issuer"], audience: _configuration["Jwt:Audience"], claims: claims, expires: DateTime.UtcNow.AddDays(7), signingCredentials: creds); return new JwtSecurityTokenHandler().WriteToken(token);}public ClaimsPrincipal ValidateToken(string token){ var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]); var tokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = true, ValidateAudience = true, ValidIssuer = _configuration["Jwt:Issuer"], ValidAudience = _configuration["Jwt:Audience"], ValidateLifetime = true, ClockSkew = TimeSpan.Zero }; try { var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out _); return principal; } catch { return null; }}Program.cs
var builder = WebApplication.CreateBuilder(args);var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));builder.Services.AddIdentity<ApplicationUser, IdentityRole>(options =>{ options.SignIn.RequireConfirmedAccount = false; }).AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();builder.Services.AddScoped<TokenService>();builder.Services.AddScoped<CookieService>();var key = Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]);builder.Services.AddAuthentication(options =>{ options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = 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) };}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>{ options.Cookie.Name = "auth_token"; options.LoginPath = "/login"; options.AccessDeniedPath = "/access-denied"; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.SameSite = SameSiteMode.None; options.ExpireTimeSpan = TimeSpan.FromDays(30); options.SlidingExpiration = true; });builder.Services.AddCors(options =>{ options.AddPolicy("AllowSpecificOrigin", builder => { builder.WithOrigins("localhost") .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); });});builder.Services.AddSession(options =>{ options.IdleTimeout = TimeSpan.FromDays(30); options.Cookie.HttpOnly = true; options.Cookie.IsEssential = true;});builder.Services.AddHttpContextAccessor();builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<ApplicationUser>>();string smtpServer = builder.Configuration["Email:SmtpServer"] ?? throw new ArgumentNullException(nameof(smtpServer), "SMTP Server is not configured.");int smtpPort = int.TryParse(builder.Configuration["Email:SmtpPort"], out var port) ? port : 587;string smtpUser = builder.Configuration["Email:SmtpUser"] ?? throw new ArgumentNullException(nameof(smtpUser), "SMTP User is not configured.");string smtpPass = builder.Configuration["Email:SmtpPass"] ?? throw new ArgumentNullException(nameof(smtpPass), "SMTP Password is not configured.");builder.Services.AddTransient<IEmailSender, EmailSender>(i => new EmailSender(smtpServer, smtpPort, smtpUser, smtpPass));builder.Services.AddSingleton<RoleInitializer>();builder.Services.AddRazorPages();builder.Services.AddHttpClient<AuthService>();builder.Services.AddServerSideBlazor();builder.Services.AddControllers();builder.Services.AddSingleton<WeatherForecastService>();builder.Services.AddSingleton<IBootstrapBase, BootstrapBase>();builder.Services.AddScoped<MenuService>();var app = builder.Build();using (var scope = app.Services.CreateScope()){ var services = scope.ServiceProvider; var roleInitializer = services.GetRequiredService<RoleInitializer>(); await roleInitializer.InitializeAsync( services.GetRequiredService<UserManager<ApplicationUser>>(), services.GetRequiredService<RoleManager<IdentityRole>>());}if (!app.Environment.IsDevelopment()){ app.UseExceptionHandler("/Error"); app.UseHsts();}app.UseHttpsRedirection();app.UseStaticFiles();app.UseRouting();app.UseAuthentication();app.UseAuthorization();app.UseCors("AllowSpecificOrigin");app.UseSession();app.MapControllers();app.MapBlazorHub();app.MapFallbackToPage("/_Host");app.Run();