Forum Discussion

RichardB1640's avatar
RichardB1640
Copper Contributor
May 07, 2026

Http requests from client to server project with cookie auth

Start a new Blazor app with individual accounts.

Add a controller to the server project.

[ApiController]

[Route("api/[controller]")]

[Authorize]

public class TestController : ControllerBase

{

private readonly ILogger _logger;

 

public TestController(ILogger logger)

{

_logger = logger;

}

 

[HttpGet("public")]

[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]

[AllowAnonymous]

public IActionResult GetPublic()

{

return Ok(JsonConvert.SerializeObject("Now is the time for all good men to come to the aid of the public party."));

}

 

[HttpGet("private")]

[ProducesResponseType(typeof(string), StatusCodes.Status200OK)]

public IActionResult GetPrivate()

{

return Ok(JsonConvert.SerializeObject($"Now is the time for all good men and {User.Identity.Name} to come to the aid of the private party."));

}

And route it in in Program.cs

...

builder.Services.AddControllers(); // +

...

app.MapControllers(); // +

Create a HttpClient for the API

public class CookieHandler : DelegatingHandler

{

public CookieHandler()

{

InnerHandler = new HttpClientHandler() { AllowAutoRedirect = false };

}

 

protected override Task SendAsync(

HttpRequestMessage request, CancellationToken cancellationToken)

{

request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);

request.Headers.Add("X-Requested-With", ["XMLHttpRequest"]);

 

return base.SendAsync(request, cancellationToken);

}

}

 

public class LocalHttpClient : HttpClient

{

public LocalHttpClient(CookieHandler h) : base(h)

{

}

}

in the <em>client</em> project and register it in <em>both</em> the client and the server project.

builder.Services.AddTransient();

builder.Services.AddTransient();

Update the client side page Auth.razor to use it

@page "/auth"


@using Microsoft.AspNetCore.Authorization


@attribute [Authorize]

@* @rendermode InteractiveWebAssembly *@

@rendermode InteractiveAuto



@inject LocalHttpClient _HttpClient



@code{

protected override async Task OnInitializedAsync()

{

HttpResponseMessage rx = await _HttpClient.GetAsync("https://localhost:7131/api/Test/public");

Public = await rx.Content.ReadAsStringAsync();



rx = await _HttpClient.GetAsync("https://localhost:7131/api/Test/private");

Private = await rx.Content.ReadAsStringAsync();

if(!rx.IsSuccessStatusCode)

{

Private = (Private ?? "") + rx.StatusCode.ToString();

}



await base.OnInitializedAsync();

}



string Public { get; set; }

string Private { get; set; }

}



<PageTitle>Auth</PageTitle>



<h1>You are authenticated</h1>



<p>Public: <code>@Public</code></p>



<p>Private: <code>@Private</code></p>



<AuthorizeView Context="AuthorizeViewContext">

Hello @AuthorizeViewContext.User.Identity?.Name!

</AuthorizeView>


The authorisation doesn't work.

 

1 Reply

  • Hi , my best guess is

    Your `@rendermode InteractiveAuto` runs **twice**.

    On the **server prerender**, the backend calls itself. Since it's not running in a browser at that moment, there are **no cookies** attached to that initial `HttpClient` request. Boom, `401 Unauthorized`.

    Fix 1: Disable Prerendering 

    If you don't care about SEO or immediate static HTML, just disable prerendering so it only runs on the WebAssembly client where cookies work naturally.

    Change the top of your `Auth.razor` to:

    @rendermode @(new InteractiveAutoRenderMode(prerender: false))

     

     Fix 2: Forward Cookies during Prerender (Best Practice)

    If you *must* keep prerendering, you need to forward the cookie from the user's incoming browser request to the backend `HttpClient`.

     

    1. Add this in the **Server's** `Program.cs`:

    builder.Services.AddHttpContextAccessor();

     

    2. Register your `LocalHttpClient` on the **Server** side to clone the cookie:

     

    builder.Services.AddHttpClient<LocalHttpClient>(client =>
    
    {
    
    client.BaseAddress = new Uri("https://localhost:7131/");
    
    })
    
    .ConfigurePrimaryHttpMessageHandler(sp =>
    
    {
    
    var httpContext = sp.GetRequiredService<IHttpContextAccessor>().HttpContext;
    
    var handler = new HttpClientHandler();
    
    
    
    if (httpContext != null && httpContext.Request.Cookies.TryGetValue(".AspNetCore.Identity.Application", out var cookie))
    
    {
    
    handler.CookieContainer = new System.Net.CookieContainer();
    
    handler.CookieContainer.Add(new Uri("https://localhost:7131/"), new System.Net.Cookie(".AspNetCore.Identity.Application", cookie));
    
    }
    
    
    
    return handler;
    
    });

     

    *(Keep your original WebAssembly client registration as is, since the browser handles the cookie there).*