MSAL Configuration and Logging

I previously posted about the logging capabilities in ADALv3. Logging is part of MSAL as well, and works in the same way.

Due to the converged authN capabilities of MSAL, it is very easy to mis-configure things. For example:

  • If you request permission for a resource from Office 365, the default authority (login.microsoftonline.com/common) won't work
  • If you replace common with your tenant name/id, then you need to append 'v2.0'
  • The implicit login is easily enabled, but won't work with app-only permission requests. (While this has always been the case, most v1 apps did not have the implicit login enabled since it was a multi-step process instead of checking a box.)

Having the logs from MSAL can be very helpful to resolve these issues. In this post, I cover adding logging to an ASPNET Core MVC application using the built-in dependency injection.

First, we need a class to perform the logging.

public class MSALLogCallback
{
  private static StringBuilder log = new StringBuilder();
  public string GetLog()
  {
    var result = log.ToString();
    log.Clear();
    return result;
  }

  public void Log(Logger.LogLevel level, string message, bool containsPii)
  {
    if (!containsPii)
    {
      string requestId = Activity.Current?.Id;
      log.AppendLine($"{requestId} - {level.ToString()} - {message}");
    }
  }
}

The logging class must be provided to the MSAL library, but can only be added once. In ASPNET Core, the natural place for this is in the Startup class. The following updates to Startup.cs will enable the logging.

  1. Add the logging class to the DI container in the ``ConfigureServices` method
services.AddSingleton<MSALLogCallback>();
  1. In the Configure method, get the instance from the DI container. This requires the method signature to include an IServiceProvider. The Core DI process will inject it into the method.
public void Configure(IHostingEnvironment env, IApplicationBuilder app, IServiceProvider serviceProvider)
  1. When running in the development environment, pass the logging class to MSAL
    if (env.IsDevelopment())
    {
      var msalLogger = serviceProvider.GetService<MSALLogCallback>();
      Microsoft.Identity.Client.Logger.LogCallback = msalLogger.Log;

      app.UseDeveloperExceptionPage();

      // other configuration...
    }

With our configuration complete, we can now update the controller(s) to get and display the log entries.

  1. Have the DI system provide us with the logger class by adding it as a parameter to the constructor:
public HomeController(MSALLogCallback msalLog)
{
  _msalLog = msalLog
}
  1. Just before the end of action methods that use MSAL, output the log to the Visual Studio output window.
[Authorize]
public async Task<IActionResult> Index()
{
  // various stuff...

  System.Diagnostics.Debug.WriteLine(_msalLog.GetLog());

  return View();
}

With these updates, the Debug section of the Output window in Visual Studio will show the MSAL activity.