[Blazor] In wasm (client-side blazor) HttpClient post request does not save cookie in browser
See original GitHub issueDescribe the bug
I have a Blazor hosted project set-up with identity authentication. Using 3.0 preview 4, after an HttpClient request to the server Login api, the response correctly contains a Set-Cookie
header with the identity cookie. However the cookie is not stored in the browser making subsequent requests unauthorized. This was working in preview 3. I am doing something wrong ?
My Setup
Startup.cs (Server project)
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseLazyLoadingProxies().UseSqlite("Filename=data.db"));
services.AddCors();
services.AddIdentity<ApplicationUser, IdentityRole<Guid>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = false;
options.Cookie.IsEssential = true;
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
});
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
options.User.RequireUniqueEmail = false;
});
services.AddControllersWithViews().AddNewtonsoftJson();
//TODO: Remove when fixed
//AllowSynchronousIO is required for newtonsoft serialization
services.Configure<KestrelServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
services.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
services.AddResponseCaching();
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(120);
});
services.AddResponseCompression(options =>
{
options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
{
MediaTypeNames.Application.Octet,
WasmMediaTypeNames.Application.Wasm,
});
});
//....
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors();
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBlazorDebugging();
}
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
app.UseBlazor<Client.Startup>();
}
AuthorizeController.cs
[AllowAnonymous]
[Route("api/[controller]/[action]")]
[ApiController]
public class AuthorizeController : ControllerBase
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
public AuthorizeController(UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
[HttpPost]
public async Task<IActionResult> Login(LoginParameters parameters)
{
var user = await _userManager.FindByNameAsync(parameters.Username);
if (user == null) return BadRequest("User does not exist");
var singInResult = await _signInManager.CheckPasswordSignInAsync(user, parameters.Password, false);
if (!singInResult.Succeeded) return BadRequest("Invalid password");
await _signInManager.SignInAsync(user, true);
return Ok();
}
//...
Client-side project HttpClient code
public class AuthorizeApi : IAuthorizeApi
{
private readonly HttpClient _httpClient;
public AuthorizeApi(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task Login(string username, string password)
{
var stringContent = new StringContent(Json.Serialize(new LoginParameters
{
Username = username,
Password = password
}), Encoding.UTF8, "application/json");
var result = await _httpClient.PostAsync("api/Authorize/Login", stringContent);
if (result.StatusCode == System.Net.HttpStatusCode.BadRequest)
throw new Exception(await result.Content.ReadAsStringAsync());
result.EnsureSuccessStatusCode();
}
//...
Request info
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:8
Top Results From Across the Web
HttpClient doesn't include cookies with requests in Blazor ...
This cookie contains the user's email address, and is used by the user info service to retrieve a more detailed set of user...
Read more >Securing API calls with Blazor WASM (question) : r/dotnet
I have a Blazor WASM app that calls a .net API all hosted on Azure. ... HTTP requests made from a server does...
Read more >ASP.NET Core Blazor WebAssembly additional security ...
This article describes additional security scenarios for Blazor WebAssembly apps. Attach tokens to outgoing requests.
Read more >Blazor: switching Server and WebAssembly at runtime
The problem remains to be solved: when Blazor Server executes client-side code of the application, which makes calls to the API over HTTP,...
Read more >Authentication with client-side Blazor using WebAPI and ...
In this post, I show how you can build a client-side Blazor app with authentication using WebAPI and ASP.NET Core Identity.
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Turns out, it was a problem with chrome on my PC. I have no idea why it didn’t work, maybe some extension was jamming it. When I used Firefox (or Chrome in Incognito mode) everything worked fine.
I have never seen something like that before. I did a clean re-install of Chrome and now it is working again.
Sorry if I wasted anyone’s time.
I cannot reproduce the issue. I have uploaded a branch of the sample project using preview 4 and everything works fine.
I will keep trying to find the issue, but until then I am gonna close this. I don’t want to waste your time with a possible misconfiguration. I will reopen if needed.