MeanGreen
MeanGreen

Reputation: 3305

Claims added in Startup not found in Blazor page

In order to get group membership functionality in our Blazor app based on Azure B2C, I add some claims in the Server project in Startup.cs. When I inspect the User object in the razor pages, the claims I added are not present.

Startup.cs, public void Configure():

            app.Use(async (context, next) =>
        {
            if (context.User != null && context.User.Identity.IsAuthenticated)
            {
                var groups = GetGroupsFromAzureB2c(context.User);
                
                // Attempt A, separate Identity
                ClaimsIdentity i = new(context.User.Identity);
                i.AddClaims(groups.Select(g => new Claim("Group", g)));
                context.User.AddIdentity(i);

                // Attempt B: Adding claims to the existing Identity
                ((ClaimsIdentity)context.User.Identity).AddClaims(groups.Select(g => new Claim("Group", g));
            }
            await next();
        });

page.razor, protected override async Task OnInitializedAsync():

        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
    var user = authState.User;

    if (user.Identity.IsAuthenticated)
    {
        var _claims = user.Claims;
    }

_claims only holds the 12 claims that were added automatically, never the 4 claims I added in Startup.cs.

Are there different instances of the User object? Am I adding the claims incorrectly?

Upvotes: 1

Views: 1231

Answers (1)

MeanGreen
MeanGreen

Reputation: 3305

Apparently there are two separate Identities at play in a Blazor app. One in the Client code and a separate one in the Server code.

We fixed this by adding a CustomUserFactory that inherits from AccountClaimsPrincipalFactory<RemoteUserAccount>. We retrieve the AzureB2C roles from a central method using the Graph API for the client side which we call in Program.cs with

    builder.Services.AddMsalAuthentication(options =>
    {
        builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
        options.ProviderOptions.DefaultAccessTokenScopes.Add("xxx");
    })
        // here we hook up our custom factory
        .AddAccountClaimsPrincipalFactory<CustomUserFactory>(); 

For the server side code, we use the same central method to get the roles from AzureB2C which we call from Startup.cs with

    services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options => {
        options.Events.OnTokenValidated = async context => {/*add roles here*/}

Upvotes: 0

Related Questions