Custom Authentication in Blazor WebAssembly – Detailed

by | Updated on Jun 20, 2020 | Blazor

In this next part of the Blazor Blog Series, Let’s learn about implementing Custom Authentication in Blazor WebAssembly Project (Blazor.Learner). We will cover some core concepts that can get you familiar with how authentication works in Blazor Applications.

PS, This is quite a detailed Article with around 3000 words. So I suggest you to bookmark this page for future reference. Grab a drink and let’s get started!

Built-in Authentication

Microsoft Ships Blazor with Built-in Authentication that can get you started quickly. But this is not what we will be looking into today. The Built-in Approach has quite a lot of limitations. For instance, what if you already have a Blazor project and want to implement authentication? You would not be able to do so. However, here is how you can set up the out-of-the-box Authentication in Blazor WebAssembly.

builtin

The other limitations of the built-in authentication in Blazor are as follows.

  1. You will always have to use the Entity Framework Core – Code First Approach. This is not ideal for most of the developers.
  2. This uses the old Razor Pages, not the new Razor components.
  3. If you already have a database with existing users, it might be really tough to integrate this authencation.

That is why we have Custom Authentication in Blazor. Let’s begin.

Implementing Custom Authentication in Blazor WebAssembly

We will start off from where we left in our previous Part – Blazor CRUD with Entity Framework Core – Detailed Tutorial. You can get the source code here. (blazor-blog-series-part-3 branch)

PS, The provided GitHub link takes you to the repository branch where we left off. The master is the current branch.

Login & Register Models

As usual, we need to build the model classes that would take in various authentication parameters for login and registering new users. We will create these classes in the Shared Project under the Models folder. You will need to install a package to help us with the Data Annotations. (Validations for the Models)

Install-Package System.ComponentModel.Annotations

Let’s add the Register Model, Models/RegisterRequest.cs

public class RegisterRequest
{
    [Required]
    public string UserName { get; set; }
    [Required]
    public string Password { get; set; }
    [Required]
    [Compare(nameof(Password), ErrorMessage = "Passwords do not match!")]
    public string PasswordConfirm { get; set; }
}

Now create a model for Login, Models/LoginRequest.cs

public class LoginRequest
{
    [Required]
    public string UserName { get; set; }
    [Required]
    public string Password { get; set; }
    public bool RememberMe { get; set; }
}

Finally we will need one mode model in the Share Project that is going to hold the details of the current user. Models/CurrentUser.cs

public class CurrentUser
{
    public bool IsAuthenticated { get; set; }
    public string UserName { get; set; }
    public Dictionary<string, string> Claims { get; set; }
}

That’s all to do in the Shared Project. Now we have classes to help hold authentication parameters. In this tutorial, we will go by using Microsoft Identity. You could switch this with your own logic if needed. Let’s a mode for our User. Since this Model will inherit from IdentityUser, we will be adding it to the Server Project. But before that, let’s add the required packages to our Server Project. PS, you may want to update all your existing packages before installing new ones.

Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson

Now in the Server Project, add a new class at Models/ApplicationUser.cs

public class ApplicationUser : IdentityUser
{
}

Let’s modify our ApplicationDbContext class to support identity. Navigate to Data/ApplicationDBContext.cs and make the following changes.

public class ApplicationDBContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDBContext(DbContextOptions<ApplicationDBContext> options):base(options)
    {
    }
    public DbSet<Developer> Developers { get; set; }
}

After that, navigate to Server/Startup.cs and make the following changes.

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDBContext>();
    services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.HttpOnly = false;
        options.Events.OnRedirectToLogin = context =>
        {
            context.Response.StatusCode = 401;
            return Task.CompletedTask;
        };
    });
    services.AddControllers().AddNewtonsoftJson();
    services.AddControllersWithViews();
    services.AddRazorPages();         
}

We will be using Cookies for state management. You could use Session Storage as well. Do not forget to add Authentication adn Authorization Middlewares to the application. Navigate to the Configure method of Startup.cs and add these lines below app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

Make sure that you add these lines in the same order. With that done, we can proceed to migrations and updating the database, so that we create the required Identity tabes.

add-migration Identity
update-database

The only thing that is left to do in Server Project is to actually add the API endpoint to log in, register, logout, and get current user details. Let’s add a new Controller for this at Controllers/AuthController.cs

[Route("api/[controller]/[action]")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    public AuthController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }
}

Line #1 – For accesing the endpoints like ..api/auth/login or …api/auth/register
Line #5-11 Constructor Injection of the Identity Interfaces for signing-in and creating new users etc.

No we will add the required Action Methods. Note that these are all very basic methods. You could probably implement your logic here if needed to match your business requirement.

Login – Controller Method

[HttpPost]
public async Task<IActionResult> Login(LoginRequest request)
{
    var user = await _userManager.FindByNameAsync(request.UserName);
    if (user == null) return BadRequest("User does not exist");
    var singInResult = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false);
    if (!singInResult.Succeeded) return BadRequest("Invalid password");
    await _signInManager.SignInAsync(user, request.RememberMe);
    return Ok();
}

Register – Controller Method

[HttpPost]
public async Task<IActionResult> Register(RegisterRequest parameters)
{
    var user = new ApplicationUser();
    user.UserName = parameters.UserName;
    var result = await _userManager.CreateAsync(user, parameters.Password);
    if (!result.Succeeded) return BadRequest(result.Errors.FirstOrDefault()?.Description);
    return await Login(new LoginRequest
    {
        UserName = parameters.UserName,
        Password = parameters.Password
    });
}

Here we are also returning a Login Model after successful registration. This is to implement auto-login after the user registers.

Logout – Controller Method

[Authorize]
[HttpPost]
public async Task<IActionResult> Logout()
{
    await _signInManager.SignOutAsync();
    return Ok();
}

Get Current User – Controller Method

[HttpGet]
public CurrentUser CurrentUserInfo()
{
    return new CurrentUser
    {
        IsAuthenticated = User.Identity.IsAuthenticated,
        UserName = User.Identity.Name,
        Claims = User.Claims
        .ToDictionary(c => c.Type, c => c.Value)
    };
}

Returns the current logged in user with authentication state. We will also fetch the claims that can possibly contain the Roles as well. With this we can say that the coding needed in the Server Project is done. The only aim of the server project is to provide the data. We have built the Auth Endpoint that GETS or POSTS data from/to the Datasource.

Now, The Main Part – Authentication in Blazor WebAssembly

Firstly, there is one packages that is needed to be installed on the Client Project. Let’s install it.

Install-package Microsoft.AspNetCore.Components.Authorization

As mentioned previously, we now have api endpoints to facilitate authentication stuff. Now the only task left for us is to utilize these endpoints in our Client Project, right? As usual, to access endpoints, let’s add a service and it’s interface. We will name it AuthService and IAuthService. So the idea is that we will access these api endpoints by using an instance of injected HTTP Client in the service class from our Client Project.

Add a new interface in the client project. Services/IAuthService.cs

public interface IAuthService
{
    Task Login(LoginRequest loginRequest);
    Task Register(RegisterRequest registerRequest);
    Task Logout();
    Task<CurrentUser> CurrentUserInfo();
}

Let’s add a concrete class and implement the previous interface. These implementations would just be using the injected httpclient and calling the required api endpoints with POST / GET JSON methods.

public class AuthService : IAuthService
{
    private readonly HttpClient _httpClient;

    public AuthService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async Task<CurrentUser> CurrentUserInfo()
    {
        var result = await _httpClient.GetFromJsonAsync<CurrentUser>("api/auth/currentuserinfo");
        return result;
    }

    public async Task Login(LoginRequest loginRequest)
    {
        var result = await _httpClient.PostAsJsonAsync("api/auth/login", loginRequest);
        if (result.StatusCode == System.Net.HttpStatusCode.BadRequest) throw new Exception(await result.Content.ReadAsStringAsync());
        result.EnsureSuccessStatusCode();
    }

    public async Task Logout()
    {
        var result = await _httpClient.PostAsync("api/auth/logout", null);
        result.EnsureSuccessStatusCode();
    }

    public async Task Register(RegisterRequest registerRequest)
    {
        var result = await _httpClient.PostAsJsonAsync("api/auth/register", registerRequest);
        if (result.StatusCode == System.Net.HttpStatusCode.BadRequest) throw new Exception(await result.Content.ReadAsStringAsync());
        result.EnsureSuccessStatusCode();
    }

}

Authentication State Provider

As the name suggests, this class provides the state of authentication of the user in Blazor Applications. AuthenticationStateProvider is an abstract class in the Authorization namespace. Blazor uses this class which would be inherited and overriden by us with custom implementation for getting the user state. This state can be from either local storage, session storage or cookies like in our case.

Let’s start by adding the Provider class in the Services folder. Let’s name it CustomStateProvider. As mentioned, this class will inherit the AuthenticationStateProvider class.

public class CustomStateProvider : AuthenticationStateProvider
{
    private readonly IAuthService api;
    private CurrentUser _currentUser;
    public CustomStateProvider(IAuthService api)
    {
        this.api = api;
    }
    public override Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        throw new NotImplementedException();
    }
}

You can see that , by default we get to implement a function GetAuthenticationStateAsync. Now this function is quite important as Blazor calls this very often to check the state of authentication of user in the application. Get the point?

Also, we will be injecting the AuthService and the CurrentUser Model to the constructor of this class. The idea behind this is that we will not be directly using the service instance in the view (Razor Components), rather we will inject the instance of CustomStateProvider to our views that would in turn access the services.

Here is the finished State Provider class. I will explain it in a bit.

public class CustomStateProvider : AuthenticationStateProvider
{
    private readonly IAuthService api;
    private CurrentUser _currentUser;
    public CustomStateProvider(IAuthService api)
    {
        this.api = api;
    }
    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var identity = new ClaimsIdentity();
        try
        {
            var userInfo = await GetCurrentUser();
            if (userInfo.IsAuthenticated)
            {
                var claims = new[] { new Claim(ClaimTypes.Name, _currentUser.UserName) }.Concat(_currentUser.Claims.Select(c => new Claim(c.Key, c.Value)));
                identity = new ClaimsIdentity(claims, "Server authentication");
            }
        }
        catch (HttpRequestException ex)
        {
            Console.WriteLine("Request failed:" + ex.ToString());
        }

        return new AuthenticationState(new ClaimsPrincipal(identity));
    }

    private async Task<CurrentUser> GetCurrentUser()
    {
        if (_currentUser != null && _currentUser.IsAuthenticated) return _currentUser;
        _currentUser = await api.CurrentUserInfo();
        return _currentUser;
    }
    public async Task Logout()
    {
        await api.Logout();
        _currentUser = null;
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
    public async Task Login(LoginRequest loginParameters)
    {
        await api.Login(loginParameters);
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
    public async Task Register(RegisterRequest registerParameters)
    {
        await api.Register(registerParameters);
        NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
    }
}

GetAuthenticationStateAsync – Get the current user from the service object. if the user is authenticated, we will add his/her claims into a list and create and Claims Identity. After this, we will return an Authentication State with the required data.

Other 3 Methods are pretty straight forward. We will just be calling the required service methods. But here is one extra thing that I would want to explain. Now with every login, registration, logout, technically there is a state change in authentication. We need to let the entire application know that the user’s state has changed. Hence we use a Notify Method and pass the current authentication state by calling the GetAuthenticationStateAsync. Pretty logical, yeah?

Now, to activate these services and dependencies in the Client Project, we need to register them into the container yeah? For this, Navigate to the client project’s Program.cs and make the following additions.

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("app");

        builder.Services.AddOptions();
        builder.Services.AddAuthorizationCore();
        builder.Services.AddScoped<CustomStateProvider>();
        builder.Services.AddScoped<AuthenticationStateProvider>(s => s.GetRequiredService<CustomStateProvider>());
        builder.Services.AddScoped<IAuthService, AuthService>();

        builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

        await builder.Build().RunAsync();
    }
}

That’s done too! Now let’s work on adding the Razor Components for the UI. Here we will ave to add 2 Components , i.e, Login and the Register component. We will be protecting the entire application by securing it. That means only an authenticated user will be allowed to view any data on the page. So, we will have a seperate Layout Component for the Login/Register components. Let’s add this first.

Navigate to the Shared Folder with the Client project. Here is where you would ideally add any shared Razor Components. In our case, let’s add a new Razor Component and call it , AuthLayout.razor

@inherits LayoutComponentBase
    <div class="main">
        <div class="content px-4">
            @Body
        </div>
    </div>

You can see that it is quite a basic html file with a inherit tag. We will not concentrate on css/html in this series. However, this layout component is going to act as a container that will hold the Login and Register component within itself.Feel free to do all the fancy html stuff here.

PS, If you are going to add in css styles, I suggest you to add these properties in the site.css file located at the wwwroot/css folder to keep things organized.

Login Component

Create a new Razor Component under Pages/Authentication/Login.razor

@page "/login"
@layout AuthLayout
@inject NavigationManager navigationManager
@inject CustomStateProvider authStateProvider

<h1 class="h2 font-weight-normal login-title">
    Login
</h1>

<EditForm class="form-signin" OnValidSubmit="OnSubmit" Model="loginRequest">
    <DataAnnotationsValidator />

    <label for="inputUsername" class="sr-only">User Name</label>
    <InputText id="inputUsername" class="form-control" @bind-Value="loginRequest.UserName" autofocus placeholder="Username" />
    <ValidationMessage For="@(() => loginRequest.UserName)" />

    <label for="inputPassword" class="sr-only">Password</label>
    <InputText type="password" id="inputPassword" class="form-control" placeholder="Password" @bind-Value="loginRequest.Password" />
    <ValidationMessage For="@(() => loginRequest.Password)" />

    <div class="form-check m-3">
        <InputCheckbox id="inputRememberMe" class="form-check-input" @bind-Value="@loginRequest.RememberMe" />
        <label class="form-check-label" for="inputRememberMe">Remember Me</label>
    </div>

    <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>

    <label class="text-danger">@error</label>

    <NavLink href="register">
        <h6 class="font-weight-normal text-center">Create account</h6>
    </NavLink>
</EditForm>

@code{
    LoginRequest loginRequest { get; set; } = new LoginRequest();
    string error { get; set; }

    async Task OnSubmit()
    {
        error = null;
        try
        {
            await authStateProvider.Login(loginRequest);
            navigationManager.NavigateTo("");
        }
        catch (Exception ex)
        {
            error = ex.Message;
        }
    }
}

Line 1 – Page route – ../login
Line 2 – Set the Layout to AuthLayout component
Line 4 Injects our CustomStateProvider instance.

Then we have a bunch of htmls that defines a form with username and password input.

From Line 35, We define the Model object (LoginRequest) and build the function OnSubmit that get’s fired when you submit the form with valid data. Here we just use the customstateprovider to access the service and ultimately the api to verify the login.

Register Component

Similarly we create a register component too under Pages/Authentication/Register.razor

@page "/register"
@layout AuthLayout
@inject NavigationManager navigationManager
@inject CustomStateProvider authStateProvider

<h1 class="h2 font-weight-normal login-title">
   Register
</h1>

<EditForm class="form-signin" OnValidSubmit="OnSubmit" Model="registerRequest">
    <DataAnnotationsValidator />

    <label for="inputUsername" class="sr-only">User Name</label>
    <InputText id="inputUsername" class="form-control" placeholder="Username" autofocus @bind-Value="@registerRequest.UserName" />
    <ValidationMessage For="@(() => registerRequest.UserName)" />

    <label for="inputPassword" class="sr-only">Password</label>
    <InputText type="password" id="inputPassword" class="form-control" placeholder="Password" @bind-Value="@registerRequest.Password" />
    <ValidationMessage For="@(() => registerRequest.Password)" />

    <label for="inputPasswordConfirm" class="sr-only">Password Confirmation</label>
    <InputText type="password" id="inputPasswordConfirm" class="form-control" placeholder="Password Confirmation" @bind-Value="@registerRequest.PasswordConfirm" />
    <ValidationMessage For="@(() => registerRequest.PasswordConfirm)" />

    <button class="btn btn-lg btn-primary btn-block" type="submit">Create account</button>

    <label class="text-danger">@error</label>
    <NavLink href="login">
        <h6 class="font-weight-normal text-center">Already have an account? Click here to login</h6>
    </NavLink>
</EditForm>

@functions{

    RegisterRequest registerRequest { get; set; } = new RegisterRequest();
    string error { get; set; }

    async Task OnSubmit()
    {
        error = null;
        try
        {
            await authStateProvider.Register(registerRequest);
            navigationManager.NavigateTo("");
        }
        catch (Exception ex)
        {
            error = ex.Message;
        }
    }
}

You can see there are a bunch of unresolvable errors that probably say that few items are not defined in namespace or something. This is because we have not imported the new namespaces. To do this,navigate to _Import.razor and add these lines to the bottom.

@using Blazor.Learner.Client.Services
@using Microsoft.AspNetCore.Components.Authorization

Now, the error will go away. Now, we need to let Blazor know that we have authentication enabled and need to pass Authorize attribute throughout the application. For this, modify the Main Component, i.e, App.razor component.

<Router AppAssembly="@typeof(Program).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
    </Found>
    <NotFound>
        <CascadingAuthenticationState>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </CascadingAuthenticationState>
    </NotFound>
</Router>

What is AuthorizeRoteView?
It’s a combination of AuthorizeView and RouteView, so that is displays the specific page but only to users who are authorized.

What is CascadingAuthenticationState?
This provides a cascading parameter to all descendant components.

Let’s add a logout button to the top navigation of the application to allow the user to log out. We will have to make changes to the MainLayout.razor component for this.

@inherits LayoutComponentBase
@inject NavigationManager navigationManager
@inject CustomStateProvider authStateProvider

<div class="sidebar">
    <NavMenu />
</div>

<div class="main">
    <div class="top-row">
        <button type="button" class="btn btn-link ml-md-auto" @onclick="@LogoutClick">Logout</button>
    </div>

    <div class="content px-4">
        @Body
    </div>
</div>
@functions{

    [CascadingParameter]
    Task<AuthenticationState> AuthenticationState { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        if (!(await AuthenticationState).User.Identity.IsAuthenticated)
        {
            navigationManager.NavigateTo("/login");
        }
    }
    async Task LogoutClick()
    {
        await authStateProvider.Logout();
        navigationManager.NavigateTo("/login");
    }
}

And finally, we will need to display our username on the Index Component soon after we login. Navigate to Pages/Index.razor and make the following changes.

@page "/"
<AuthorizeView>
    <Authorized>
        <h1>Hello @context.User.Identity.Name !!</h1>
        <p>Welcome to Blazor Learner.</p>
        <SurveyPrompt Title="How is Blazor working for you?" />
    </Authorized>
    <Authorizing>
        <h1>Loading ...</h1>
    </Authorizing>
</AuthorizeView>

Let’s test our Application now.

login
register
index

If you found this article helpful,

Buy me a coffeeBuy me a coffee

Summary

In this article, we have gone in depth to the Custom Authentication in Blazor WebAssembly. I will be updating this article with more data for you to learn. I hope this covers the entire Custom Authentication in Blazor WebAssembly. Let me know if I missed out on anything. You can find the completed source code here. Share this article within tour developer communituy so that other developers can get a taste of Blazor! Happy Coding 😀

5 Comments

  1. Hoshmand

    Thank you, Dear Mukesh,

    This is something great that I wanted to recommend you to publish an article about it,
    I am very excited to read this article after this comment, then I will implement it, I hope you have included the custom users role management as well in this article,

    I had a requirement that wanted to build a complete dynamic user management

    I am going to write the following software requirement SRS, use cases for that,

    There is a need to be the default super admin with full access withing application, After login,

    The super admin adds the new roles into the system such as Module Admin, Editor, office manager, Normal user, and so on.

    The super admin give role access privilege Read, Create, Update, Delete, to the particular controller or particular method,

    The super admin create the new user account and assign to the specific role,

    The public users can register by a customs form or Goole API or Facebook API authentication,

    After user login, their need to be a user profile page with file upload option, to change their profile picture, and other information,

    Every user when login into the system will view, read, update delete, those data, and menu, which has the role access for it, otherwise will view an Ops page or not found page,

    Note: I have designed the SQL database for this, I am very excited to implement it with Blazor, I am going to read your article, if you don’t cover these features, please publish the next article to complete the dynamic user management, or add your comment here to explain how to achieve this goal,

    Reply
    • Mukesh Murugan

      Hello again 😀

      I would suggest following these steps.
      1. Seed the Role “SuperAdmin” and other roles to whichver the appropriate table is.
      2. In my service layer, it’s possible to add custom logic, maybe you could load the roles to claims there. Or even create a seperate list of roles object.
      Your requirement seems very similar to the user/role management of Identity. Give it a look. I will try posting this as the next part to the seris.

      I was not able to include role management because this post itself was quite too long 😀 Hope you read it. How did you like it? Any suggestions?

      Reply
      • Hoshmand

        Greetings,

        Yes I have read, it was great article, you have done a lot of work here, I appreciate your efforts.

        I just want to add some suggestions for the next articles of user/role management module.

        I have used the Microsoft built-in Identity in my project, as you mentioned there are some limitations to implement with custom requirements like a dynamic user/role management,

        As I mentioned the requirements in my first comment. In this comment I will explain the Database Tables which is needed.

        I have designed a complete SQL database which includes the below tables or models class,

        if we code this and implement, it will be a great custom dynamic user/role management that can be use for any application, as a user/role management module.

        Database Tables or Models:

        1- Controllers And Actions Table:
        Id, Controller Name, Action Name, ActionType (GET or Post), Permission Name (Read,Create,Update,Delete).
        Developer will insert all the Controllers and Actions in this Table during development.

        2- Roles Table: Id, Role Name.
        Default Super Admin will create all the system roles through a web form.

        3- Role Access Table: Id, Role-Id, controllsAndActionId, bool=hasaccess.
        Super Admin will assigne the role access in this table, which one role can has access to one or many Controllers and methods,

        4- Users Table: Id, name, username, pass, profil picture, Role-Id and so on.
        Super admin will create user account and add a specific role to it,
        Or user can register from a public form as a guset role then super admin will give another’s role to the user if needed,

        Some logic:

        When the authorized user login into the system we will check what is his role and what is the access of his role to view, creat,update….

        If user is not authorized to any specific view Page and Controllers, and try to access it, the system will display a notify or an anathurzed message to the user,

        After successfully login:
        User Profile Page, the authorized user can update thier infromation and profile picture.

        This is what I think to build a complete dynamic user/role management module.
        You might add something more to Improve it, even if we use bootstrap popup form and notify message and replace blazor with jequry ajax, it will be extra great.
        There will be a lot of functionalities to cover such as dropdownlist, file upload, ajax form post and popup form, notify message and so on.

        Please if you have time publish an article for this requirements, either with Blazor or ASP.Net core MVC using jequry ajax call or any other JavaScript library you recomnd.

        I am sure all developers need this for thier application, I think we should buy 10 coffees, to you for this work 😂

        Regards
        Hedayat Hoshamd

        Reply
  2. stefanov

    Hi, very nice article! I immediatly tried your github code and it works (just changed to mysql database). I tried to decouple the server asp.net from the blazor WASM client. The first run on port 5000, the client on port 6000. I added CORS, changed httpclient and the api calls works. But the authentication stop working. Is it possible that the authentication works only if the solution is hosted by asp.net server only ?
    Thanks for great content!

    Reply
    • Krunal

      .client and .server are both web applications. how to make this work when they are hosted on server, e.g. azure app services.

      I think – await _signInManager.SignInAsync(user, request.RememberMe); is not going to work, resulting client application will always never be authenticated.

      Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

Follow codewithmukesh

Support Me!

Buy me a coffeeBuy me a coffee

Related Articles

Pin It on Pinterest