Role-based Authentication with hosted Blazor template

Published on Dec 27 2020Last updated on Apr 06 2022
Cover image for role-based authentication with hosted blazor template

In this tutorial I'll show you how you can add role-based authentication with the Blazor Hosted template.

First of all, we're going to create a new project:

Create a new project with Visual Studio

If you prefer CLI:

dotnet new blazorwasm --auth Individual --hosted

Create a new project in the terminal Next, we'll run dotnet ef database update in the console inside the Server projects folder so EntityFramework can run the database migrations.

dotnet new blazorwasm --auth Individual --hosted

New project created in the terminal


Then we need to make some changes in the Startup.cs class in the Server project:

You'll find a line inside the ConfigureServices method which adds the default Identity to our server:

dotnet new blazorwasm --auth Individual --hosted

We need to add one line to add our roles to the Identity:

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)

Now we need to make some changes to the following code:

    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

We'll expand it, so our Server always adds the role to the JWT token when the user requests his/her token:

    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>

I've also created a small helper method to create an admin Account, create all Roles from an Enum and assigned the Administrator role to the admin Account.

Create a new enum inside the Shared project:

// Role.cs
using System.ComponentModel;

namespace Shared
    public enum Role

Helper method inside Startup.cs of the Server project:

private void CreateRoles(IServiceProvider serviceProvider)
    var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
    var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
    Task<IdentityResult> roleResult;
    string email = "";
    string securePassword = "Pa$$w0rd!";

    foreach (var role in Enum.GetValues(typeof(Role)))
        Task<bool> roleExists = roleManager.RoleExistsAsync(role.ToString());

        if (!roleExists.Result)
            roleResult = roleManager.CreateAsync(new IdentityRole(role.ToString()));

    Task<ApplicationUser> adminUser = userManager.FindByEmailAsync(email);

    if (adminUser.Result == null)
        var admin = new ApplicationUser();
        admin.Email = email;
        admin.UserName = email;

        Task<IdentityResult> newUser = userManager.CreateAsync(admin, securePassword);

    var createdAdminUser = userManager.FindByEmailAsync(email);
    createdAdminUser.Result.EmailConfirmed = true; // confirm email so we can login
    Task<IdentityResult> newUserRoleAssignment = userManager.AddToRoleAsync(createdAdminUser.Result, Role.Administrator.ToString());

Now we need to call this helper method from the Configure method inside the Startup.cs. But first, we need to change our method signature (we need IServiceProvider inside this class, so we'll expect it from .NET Core's built in Dependency Injection:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)

Now we can add the following line at the bottom of the Configure method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)

This change will create our 3 defined Roles inside the database: Administrator, Free and Paid.

After running the app with dotnet run you can see, that all 3 roles and our admin user have been created:

(I'm using VSCode with the SQLite extension to view data from the SQLite Database file)


Roles table from the SQLite database with SQLite Extension inside of Visual Studio Code

Admin User:

Admin user from the database with SQLite Extension inside of Visual Studio Code

And the "Administrator" role assignment:

Administrator role assignment from the database with SQLite Extension inside of Visual Studio Code

Now, our server knows about Roles and will also send the roles back via the JWT token.


To read and show all Claims from our Blazor frontend, we can expand the Index.razor inside our Client project with the following (look for the tag):

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

        @foreach (var item in context.User.Claims)
            <li>Type: @item.Type, Value: @item.Value</li>

This will show us all the claims (and roles) after we've signed in. Let's run the app with dotnet run or dotnet watch run from inside the Server folder.

We're able to login with our Admin User and as you can see from the image below, our Role is exposed through the token to our Blazor frontend.

Blazor frontend showing the current role through the token

To test this out, we'll make 2 changes to the following files:

NavMenu.razor: wrap the last menu point "Fetch data" with an AuthorizeView component (built into Blazor) and a defined role:

// NavMenu.razor
<AuthorizeView Roles="Administrator">
    <li class="nav-item px-3">
                class="oi oi-list-rich"
            ></span> Fetch data

That means, that any user who has not the Role "Administrator" defined and exposed via the token, won't be able to see this menu element:

Navigation menu is hidden because user has not the administrator role defined

After logging in with the admin user, we can see the menu element again:

User is logged in, so the navigation menu shows the new entry

So, we've secured the frontend part, but we also need to secure our WeatherForecastController and allow only users with the Administrator role assigned to call all endpoints from this controller:

namespace BlazorAuth.Server.Controllers
    [Authorize] // replace this line
    [Authorize(Roles = "Administrator")] // with this line
    public class WeatherForecastController : ControllerBase

With this last change, we've secured our Fetch data page on the frontend only for users in the Administrator role and our Controller too. That means, when a user does not have this role, any call to this endpoint (Controller) or the page via the browser, won't get any data back.

Tags:blazor blazor hosted authentication role based authentication blazor wasm wasm hosted auth