1
votes

My first ever attempt at using MSAL Authorization and it fails for me in Blazor. Any Clues (it's going to be a simple answer I think?)

Small repo available here

Client File: Program.cs

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");

builder.Services.AddMsalAuthentication(options => //THROWS EXCEPTION!!!!!
{
    options.ProviderOptions.AdditionalScopesToConsent.Add($"https://graph.microsoft.com/User.Read");
});

var baseAddress = builder.HostEnvironment.BaseAddress;
builder.Services.AddHttpClient(baseAddress, client => client.BaseAddress = new Uri(baseAddress))
        .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

Unexpected Result: Exception thrown

crit:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Cannot read property 'join' of undefined TypeError: Cannot read property 'join' of undefined at Function.createUserManager (https://localhost:44391/_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js:1:6020) at Function.initializeCore (https://localhost:44391/_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js:1:5035) at Function.init (https://localhost:44391/_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js:1:4575) at https://localhost:44391/_framework/blazor.webassembly.js:1:9873 at new Promise () at Object.beginInvokeJSFromDotNet (https://localhost:44391/_framework/blazor.webassembly.js:1:9841) at _mono_wasm_invoke_js_marshalled (https://localhost:44391/_framework/wasm/dotnet.3.2.0.js:1:171294) at do_icall (wasm-function[6049]:0x10f8b1) at do_icall_wrapper (wasm-function[1896]:0x50b6a) at interp_exec_method (wasm-function[1120]:0x2588e)

1

1 Answers

1
votes

Try something like this...

builder.Services.AddMsalAuthentication(options =>
{
    ...

    options.ProviderOptions.AdditionalScopesToConsent.Add(
        "https://graph.microsoft.com/Mail.Send");
    options.ProviderOptions.AdditionalScopesToConsent.Add(
        "https://graph.microsoft.com/User.Read");
}

https://docs.microsoft.com/en-us/aspnet/core/security/blazor/webassembly/additional-scenarios?view=aspnetcore-3.1#request-additional-access-tokens

Hope it helps!

EDIT 1: My client Program.cs

using System.Net.Http; using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Add the below reference in Index.html page

<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");

            builder.Services.AddHttpClient("BlazorWasmAADMsal.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
                .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

            // Supply HttpClient instances that include access tokens when making requests to the server project
            builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("BlazorWasmAADMsal.ServerAPI"));

            builder.Services.AddMsalAuthentication(options =>
            {
                builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
                options.ProviderOptions.DefaultAccessTokenScopes.Add("api://XXXXXXXXXXXXXXXXXX/API.Access");
            });

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

EDIT 2: Did some minor changes. The working project has been uploaded here. Successful login screen shot added in answer for reference. :-)

enter image description here

EDIT 3:

Azure Active Directory (AAD) Microsoft Graph API scopes are required by an app to read user data and send mail. After adding the Microsoft Graph API permissions in the Azure AAD portal, the additional scopes are configured in the Client app.

Last time i missed to enabled below lines, I have enabled it in Program.cs

  builder.Services.AddMsalAuthentication(options =>
       {
options.ProviderOptions.DefaultAccessTokenScopes.Add("https://graph.microsoft.com/User.Read");
     }

It was a bizarre error, never expected and had seen it.

The reference of AuthenticationService.js in Index.html was not correct. I have corrected it to be...

<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>

I have also uploaded the latest code here

The IAccessTokenProvider.RequestToken method provides an overload that allows an app to provision an access token with a given set of scopes.

In a Razor component, you can write something like below:

@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider

...

var tokenResult = await TokenProvider.RequestAccessToken(
    new AccessTokenRequestOptions
    {
        Scopes = new[] { "https://graph.microsoft.com/Mail.Send", 
            "https://graph.microsoft.com/User.Read" }
    });

if (tokenResult.TryGetToken(out var token))
{
    ...
}

AccessTokenResult.TryGetToken returns:

true with the token for use. false if the token isn't retrieved.

Hope it helps you.