0

I have a Blazor WebAssembly application where I'm authenticating users on the server side using the SignInAsync method and creating a cookie. The authentication process works correctly on the server, and I can see the authentication cookie being set in the browser's storage.

However, when the client-side Blazor WebAssembly application makes subsequent requests, it doesn't automatically recognize and handle the authentication cookie. As a result, the application always treats the user as unauthenticated, even though the authentication cookie is present.

I have already configured the server-side application to set the authentication cookie correctly using SignInAsync. On the client side, I'm using CascadingAuthenticationState and AuthorizeView components to perform authorization checks. However, the application doesn't automatically authenticate the user based on the presence of the cookie.

I suspect that I may be missing some configuration or code on the client-side to enable automatic handling of the authentication cookie. How can I configure the client-side Blazor WebAssembly application to recognize and handle the authentication cookie, allowing the application to automatically authenticate the user and perform authorization checks?

I would appreciate any guidance, code examples, or suggested configurations to resolve this issue and enable seamless authentication and authorization in my Blazor WebAssembly application.

This is the Program.cs file for the server:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.EntityFrameworkCore;
using Speedy.Authorization.Common;
using SpeedyLead.Smc.Server.Services;
using SpeedyLead.Smc.Shared.Logging;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
var authorizationDbConnectionString = builder.Configuration.GetConnectionString("AuthorizationContext") ?? throw new InvalidOperationException("Connection string 'AuthorizationContext' not found.");

builder.Services.AddScoped<ILoginService, LoginService>();
builder.Services.AddScoped<ILogFactory, LogFactory>();

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddAuthentication(
    CookieAuthenticationDefaults.AuthenticationScheme
    )
    .AddCookie(
    options =>
    {
        options.LoginPath = "/login";
        options.Cookie.SameSite = SameSiteMode.None;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.HttpOnly = true;
    });

builder.Services.AddAuthorization();
builder.Services.AddSpeedyAuthorization(authorizationDbConnectionString);

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
    app.UseWebAssemblyDebugging();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseCors("CorsSpecs");
app.UseAuthentication();

app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();
app.UseSpeedyAuthorization();

app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();

And this is the client:

using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using SpeedyLead.Smc.Client;
using SpeedyLead.Smc.Client.Auth;
using SpeedyLead.Smc.Client.Services;

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddHttpClient("SpeedyLead.Smc.ServerAPI", client =>
{
    client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
})
.AddHttpMessageHandler<CookieHandler>();

// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("SpeedyLead.Smc.ServerAPI"));
builder.Services.AddLocalization();

builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<AuthenticationStateProvider, FrontendAuthenticationProvider>();
builder.Services.AddScoped<CookieHandler>();

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
builder.Services.AddBlazoredLocalStorage();

builder.Services.AddOidcAuthentication(options =>
{
    builder.Configuration.Bind("oidc", options.ProviderOptions);
});


await builder.Build().RunAsync();

CookieHandler is a class that I implemented myself (following a guide)

using Microsoft.AspNetCore.Components.WebAssembly.Http;
using Microsoft.JSInterop;

namespace SpeedyLead.Smc.Client.Auth
{
    public class CookieHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);

            return await base.SendAsync(request, cancellationToken);
        }

    }
}
  • When you send request to server, have you checked the request contains any authenticationCookie from the client, Refer to this [issue](https://stackoverflow.com/questions/63831943/httpclient-doesnt-include-cookies-with-requests-in-blazor-webassembly-app) and hope it will give you some help. – Xinran Shen May 23 '23 at 06:37

0 Answers0