Search code examples
azure-active-directoryblazorblazor-webassemblyazure-ad-msal

Blazor MSAL not requesting scopes


I've got a Blazor WASM app with .NET 7 and I'm using Azure AD with a public (multi-tenant) app registration. I'm trying to request a scope so that I can authenticate against an API. But it doesn't request include the requested scopes during authentication.

Here is my appsettings.json:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/common",
    "ClientId": "[My Balzor app client ID]",
    "ValidateAuthority": true,
    "Scopes": "openid email profile offline_access api://[My API app client ID]/user_read"
  }
}

In Program.cs I'm configuring this here:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
});

I've also tried adding it explicitly:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.AdditionalScopesToConsent.Add("api://[My API app clinet ID]/user_read");
});

However, these scopes are never requested from AAD. The URI only ever includes openid, profile, and offline_access.

Screenshot of MSAL generated URI that only includes openid, profile, and offline_access scopes, not the additional scopes I am requesting.

Why is my additional scope not requested? How do I fix this?


Solution

  • Your Scopes property is being ignored, because you are binding your "AzureAd" appsettings section to options.ProviderOptions.Authentication.

    And options.ProviderOptions.Authentication is of type Microsoft.Authentication.WebAssembly.Msal.MsalAuthenticationOptions which does not include the property DefaultAccessTokenScopes or Scopes.

    The DefaultAccessTokenScopes property (of type IList string) is a sibling to the Authentication property on the Microsoft.Authentication.WebAssembly.Msal.Models.MsalProviderOptions class.

    Thus if you restructure your AzureAd section slightly to take into account the MsalProviderOptions structure, it should all bind correctly without having to call options.ProviderOptions.DefaultAccessTokenScopes.Add() manually in the Program.cs.

    {
      "AzureAd": {
        "Authentication": {
          "Authority": "https://login.microsoftonline.com/common",
          "ClientId": "[My Balzor app client ID]",
          "ValidateAuthority": "true"
        },
        "DefaultAccessTokenScopes": ["api://[My API app client ID]/user_read", "..."]
      }
    }
    

    And then your Program.cs can be updated as follows:

    builder.Services.AddMsalAuthentication(options =>
    {
        builder.Configuration.Bind("AzureAd", options.ProviderOptions);
    });