I have a C# Blazor Application using Microsoft Identity for authenticating users against Microsoft Entra.
The application is associated (via Client Id and secret) to a Microsoft Enrta Registered App with Redirect URI of https://mywebapp/signin-oidc.
In my application I register the CallbackPath in my Program.cs like thus:
builder.Services.AddAuthentication((o) =>
{
o.DefaultAuthenticateScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddMicrosoftIdentityWebApp((o) => {
o.Instance = instance;
o.ClientId = clientId;
o.ClientSecret = clientSecret;
o.TenantId = tenantId;
o.Domain = domain;
o.CallbackPath = "/signin-oidc";
Normally the flow is as follows:
Navigation.NavigateTo("MicrosoftIdentity/Account/SignIn");
This is fine, but I also want to require sign in from other pages in the Web App.
What I want to do is to send the user a link to a specific page in my application ie. https://mywebapp/pagethree
This web page requires the user to be authenticated, so if he is not I want to direct him to the Microsoft login.
However after, he is logged in, I want him to be directed back to https://mywebapp/pagethree where he came from, but I don't know how to do it.
I've tried all kinds of permutations with MicrosoftIdentity/Account/SignIn?returnUrl or ?redirectUrl but whatever I put is ignored and the redirect is always to /signin-oidc and thence to the home page.
Any ideas for what should be a fairly basic functionality in a website.
Thanks.
Tim.
The standard way to return to the same page after login is to use the NavigateToLogin extension method provided by NavigationManagerExtensions
Add the Microsoft.AspNetCore.Components.WebAssembly.Authentication nuget package
change the click action of your login button (even if it is a simple link) to call NavigateToLogin
@inject Microsoft.AspNetCore.Components.NavigationManager Navigation
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity?.Name!
<button class="nav-link btn btn-link" @onclick="BeginLogOut">Log out</button>
</Authorized>
<NotAuthorized>
<a href="authentication/login" @onclick="BeginLogIn">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code{
public void BeginLogIn()
{
Navigation.NavigateToLogin("MicrosoftIdentity/Account/SignIn");
}
public void BeginLogOut()
{
Navigation.NavigateToLogout("MicrosoftIdentity/Account/SignOut");
}
}
In the default template, a simple hyperlink is used, you can see in the above code example that
@onclickadded to an existing link will prevent the defaulthrefnavigation and will execute the referenced code instead.
It is a lot simpler than that if you want to enforce login on certain pages and not have an unauthenticated view at all. In this case, in the razor page just add @attribute [Authorize] then if the user is unauthenticated when they reach that page or component, the user will be redirected to auth and will return to the same page.
If you want to return to a different page after the login, then you can use the NavigationManager directly instead of via the extension method. In this example there are 2 login buttons, with different return URLs configured:
@inject Microsoft.AspNetCore.Components.NavigationManager Navigation
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity?.Name!
<button class="nav-link btn btn-link" @onclick="BeginLogOut">Log out</button>
</Authorized>
<NotAuthorized>
<button class="nav-link btn btn-link" @onclick='() => BeginLogIn("/fetchdata")'>Log In - Fetch Data</button>
<button class="nav-link btn btn-link" @onclick='() => BeginLogIn("/pagethree")'>Log In - Page Three</button>
</NotAuthorized>
</AuthorizeView>
@code{
public void BeginLogIn(string returnUrl)
{
Navigation.NavigateToLogin(
"MicrosoftIdentity/Account/SignIn",
new InteractionRequestOptions
{
Interaction = InteractionType.SignIn,
ReturnUrl = returnUrl
});
}
public void BeginLogOut()
{
Navigation.NavigateToLogout("MicrosoftIdentity/Account/SignOut");
}
}
I was struggling with issues from upgrading in my Blazor WASM app .Net6 to .Net8 where my app would just 'forget' the returnurl when logging in.
I found the following breaking change: https://learn.microsoft.com/en-us/dotnet/core/compatibility/aspnet-core/7.0/wasm-app-authentication
We updated the support for authentication in Blazor WebAssembly apps to rely on the history state instead of query strings in the URL. As a result, existing applications that pass the return URL through the query string will fail to redirect back to the original page after a successful login.
Existing applications should use the new NavigateToLogin extension method as it's able to flow the data to the login page correctly.
Version introduced
.NET 7
Previous behavior
The return URL was specified in the query string as ?returnUrl=<>
New behavior
Starting in .NET 7, the return URL and other parameters passed to the authentication/login page are passed via the history.state entry of the page.
Before, I was using the default RedirectToLogin page supplied with the Blazor WASM template as such:
@inject NavigationManager Navigation
@code {
protected override void OnInitialized()
{
Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}");
}
}
The new version according to the above is:
@inject NavigationManager Navigation
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.Extensions.Options
@inject IOptionsSnapshot<RemoteAuthenticationOptions<ApiAuthorizationProviderOptions>> Options
@code {
protected override void OnInitialized()
{
Navigation.NavigateToLogin(Options.Get(Microsoft.Extensions.Options.Options.DefaultName).AuthenticationPaths.LogInPath);
}
}
Simply replacing the code worked for me. My return URL is now preserved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With