0
votes

I have a scenario where I have a Blazor WASM (client only) app that is secured via AD B2C. As per the documentation I have read, I have registered an application in AD B2C (e.g. BlazorApp) and wired the Blazor app to this instance. This Blazor app makes API calls to a .NET Core Web API where the endpoints are secured (using the [Authorize] attributes). As per the documentation I have read, I have also registered the Web API in AD B2C (e.g. WebApi) and wired the API to connect to this instance.

The problem I have is that when I authenticate in the Blazor app, and then pass the access/id token through the API calls, the Web API can't authenticate that token (unauthorized error response). It works when I wire the Web API to connect to the BlazorApp registration (I'm guessing because that is where the token was issued from). But this seems to go against the recommendation of registering each app/api in AD as a separate registration.

How can I get the WebApi registration to recognise a token issued by BlazorApp? Am I going about this wrong and should I just wire the Web API to talk to the BlazorApp instance?

Additional Information:

Blazor WASM (client) - Program.cs (sensitive information removed)

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

            ...

            builder.Services.AddMsalAuthentication(options =>
            {
                builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/blazorapp/app.read");
                options.ProviderOptions.DefaultAccessTokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/blazorapp/app.write");
            });

            ...

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

Blazor WASM (client) - appsettings.json (sensitive information removed)

{
    "AzureAdB2C": {
        "Authority": "https://<tenant name>.b2clogin.com/<tenant name>.onmicrosoft.com/B2C_1_SignUpSignIn",
        "ClientId": "<BlazorApp Application ID>",
        "ValidateAuthority": false
    }
}

Web API (.NET Core 3.1) - StartUp.cs (sensitive information removed)

public void ConfigureServices(IServiceCollection services)
        {
            ...
        services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
                .AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));

            services.AddControllers();

            ...

        }

Web API (.NET Core 3.1) - appsettings.json (sensitive information removed)

NOTE: Authentication works when I replace the WebApi Application ID with the BlazorApp Application ID

{
    "AzureAdB2C": {
        "Instance": "https://<tenant name>.b2clogin.com/tfp/",
        "ClientId": "<WebAPI Application ID>",
        "Domain": "<tenant name>.onmicrosoft.com",
        "SignUpSignInPolicyId": "B2C_1_SignUpSignIn"
    },
    ...
}
1
Please provide the code for requesting token. ‘It works when I wire the Web API to connect to the BlazorApp registration (I'm guessing because that is where the token was issued from). ’what does that mean?How you added the Web api, my understanding is that at this point your BlazorApp is both the client side and the api side.Chauncy Zhou
Your Api is not well configured, you should read this : github.com/Azure-Samples/…agua from mars
Please provide a screenshot of the BlazorApp‘s api permission in the portal, your scope it should be like tenant name.onmicrosoft.com/webApiApp.Chauncy Zhou
@aguafrommars ... what I can't work out from those samples is, is the Web App and Web API registered as two different registrations in AD B2C?Dazfl

1 Answers

1
votes

Your project is not using OBO flow, OBO flow requires three applications, specifically one client-side and two api-side, see here.

Back to the problem, first of all your problem is misconfigured scope, as the api-side app needs to expose its own api, the API permission on your blazor app side gets access to the api-side, so the access to the scope is configured on the api-side, so we need to put https://<tenant name>.onmicrosoft.com/webapiapp/app.read on the scope, your blazor app is only used to configure access.

It works because you use blazor app to request the blazor app's own api, which is feasible, although a little strange, to request yourself.

So for your project, the correct request should be like this.

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

            ...

            builder.Services.AddMsalAuthentication(options =>
            {
                builder.Configuration.Bind("AzureAdB2C", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/webapiapp/app.read");
                options.ProviderOptions.DefaultAccessTokenScopes.Add(@"https://<tenant name>.onmicrosoft.com/webapiapp/app.write");
            });

            ...

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

{
    "AzureAdB2C": {
        "Instance": "https://<tenant name>.b2clogin.com/tfp/",
        "ClientId": "<Application ID>",
        "Domain": "<tenant name>.onmicrosoft.com",
        "SignUpSignInPolicyId": "B2C_1_SignUpSignIn"
    },
    ...
}