I am building a Blazor server website in .NET 8 and I am trying to add cookie authentication without using the identity scaffolding of .NET 8.
I used the Identity scaffolding as a guideline to see how Microsoft does it and got it working, but still encountered 2 issues:
When navigating to the homepage on https://localhost:7167/, this code is hit in the App.razor
private IComponentRenderMode? RenderModeForPage => HttpContext.Request.Path.StartsWithSegments("/account")
? null
: InteractiveServer;
which is used to set the rendermode on:
<body>
<Routes @rendermode="RenderModeForPage" />
<script src="_framework/blazor.web.js"></script>
</body>
and
<HeadOutlet @rendermode="RenderModeForPage" />
based on that code the initial rendering will be done as Interactive server.
I then click the login button:
<NavLink class="nav-link" href="account/login">
<RadzenButton Text="Aanmelden" Icon="account_circle" Size="ButtonSize.Medium" ButtonStyle="ButtonStyle.Primary" />
</NavLink>
Which takes me to https://localhost:7167/account/login and this code is executed:
public async Task LoginUser()
{
try
{
var session = await AuthService.SignInAsync(Input.Email, Input.Password);
var user = CreateIdentity(session.ExternalUserId, session.Claims["email"].ToString(), session.Claims);
var authProperties = new AuthenticationProperties()
{
AllowRefresh = true,
ExpiresUtc = DateTime.UtcNow.AddMinutes(5),
IsPersistent = true,
};
await Httpcontext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user, authProperties);
Httpcontext.User = user;
NavigationManager.NavigateTo("");
}
catch (Exception ex)
{
await HandleExceptionAsync(ex);
}
}
Problem #1
Here I get a null reference exception on HttpContext, which is normal since I am still in rendering mode InteractiveServer.
This is a first point I do not understand, since when using the Identity scaffolding the navigation is done exactly the same and there the App.razor is hit again to check which render mode needs to be applied for /account/login and it is rendered as static SSR.
Problem #2
When I manually navigate to https://localhost:7167/account/login, the App.razor is hit and the page is properly rendered as static. I hit the login button and my cookie is set successfully, but I get this exception:
Exception of type 'Microsoft.AspNetCore.Components.NavigationException' was thrown.
when this line of code
NavigationManager.NavigateTo("");
is executed. I have tried all variations like NavigationManager.NavigateTo("/"), NavigationManager.NavigateTo("https://localhost:7167/") also with foreload set to true, but always the same exception.
To me, it looks like the navigation is done exactly the same in the scaffolded identity project, but then again the app.razor is hit when navigating to the login page so there must still be a difference somewhere I am just not seeing. My guess is somewhere in defining the routes or perhaps some magic in the SignInManager.
Any help on this would be greatly appreciated, I am starting to lose heart on this
