Logging in MSAL.NET

MSAL.NET apps generate log messages that can help diagnose issues. You can configure logging with a few lines of code, and have custom control over the level of detail and whether or not personal and organizational data is logged. Logging isn't enabled by default. We recommend you enable MSAL logging to provide a way for users to submit logs when they have authentication issues. Note that MSAL doesn't store any logs and emits logs to the destination provided in the logger implementation.

Note

Starting with MSAL.NET 4.58.0 developers can also use OpenTelemetry to aggregate logs and measure application performance.

Logging levels

There are several levels of logging detail:

  • LogAlways: Base level which includes logs of important health metrics to help with diagnostics of MSAL operations.
  • Critical: Logs that describe an unrecoverable application or system crash, or a catastrophic failure that requires immediate attention.
  • Error: Indicates something has gone wrong and an error was generated. Used for debugging and identifying problems.
  • Warning: Includes logs in scenarios when there hasn't necessarily been an error or failure, but are intended for diagnostics and pinpointing problems. This is the recommended minimum level that should be enabled in production apps.
  • Informational: MSAL will log events intended for informational purposes, not necessarily intended for debugging.
  • Verbose: MSAL logs the full details of library behavior. In production environment, verbose level should only be enabled temporarily to gather logs for a specific debugging purpose.

Personal and organizational data

By default, the MSAL logger doesn't capture any highly sensitive personal or organizational data. The library provides the option to enable logging personal and organizational data if you decide to do so. For details, see Handling of personally-identifiable information in MSAL.NET.

Configure logging in MSAL.NET

In MSAL, logging is set during application creation using the WithLogging(IIdentityLogger, Boolean) builder. This method takes the following parameters:

  • identityLogger is the logging implementation used by MSAL.NET to produce logs for debugging or health check purposes. Logs are only sent if logging is enabled.
  • enablePiiLogging enables logging personal and organizational data (PII) if set to true. By default, this parameter is set to false, so that your application doesn't log sensitive data.

IIdentityLogger interface

namespace Microsoft.IdentityModel.Abstractions
{
    public interface IIdentityLogger
    {
        //
        // Summary:
        //     Checks to see if logging is enabled at given eventLogLevel.
        //
        // Parameters:
        //   eventLogLevel:
        //     Log level of a message.
        bool IsEnabled(EventLogLevel eventLogLevel);

        //
        // Summary:
        //     Writes a log entry.
        //
        // Parameters:
        //   entry:
        //     Defines a structured message to be logged at the provided Microsoft.IdentityModel.Abstractions.LogEntry.EventLogLevel.
        void Log(LogEntry entry);
    }
}

Note

Higher-level libraries (Microsoft.Identity.Web, Microsoft.IdentityModel) already provide implementations of this interface for various environments (in particular ASP.NET Core).

IIdentityLogger implementation

Log level from a configuration file

It's highly recommended to configure your code to use a configuration file in your environment to set the log level as it will enable your code to change the MSAL logging level without needing to rebuild or restart the application. This is critical for diagnostic purposes, enabling to quickly gather the required logs from the application that is currently deployed in production. Verbose logging can be costly, so it's best to use the Informational level by default and enable verbose logging when an issue is encountered. See JSON configuration provider for an example on how to load data from a configuration file without restarting the application.

Log level from an environment variable

Another option we recommended is to configure your code to use an environment variable on the machine to set the log level as it will enable your code to change the MSAL logging level without needing to rebuild the application.

See EventLogLevel for details on the available log levels.

Example:

class MyIdentityLogger : IIdentityLogger
{
    public EventLogLevel MinLogLevel { get; }

    public MyIdentityLogger()
    {
        //Retrieve the log level from an environment variable
        var msalEnvLogLevel = Environment.GetEnvironmentVariable("MSAL_LOG_LEVEL");

        if (Enum.TryParse(msalEnvLogLevel, out EventLogLevel msalLogLevel))
        {
            MinLogLevel = msalLogLevel;
        }
        else
        {
            //Recommended default log level
            MinLogLevel = EventLogLevel.Informational;
        }
    }

    public bool IsEnabled(EventLogLevel eventLogLevel)
    {
        return eventLogLevel <= MinLogLevel;
    }

    public void Log(LogEntry entry)
    {
        //Log Message here:
        Console.WriteLine(entry.Message);
    }
}

Using MyIdentityLogger:

MyIdentityLogger myLogger = new MyIdentityLogger();

var app = ConfidentialClientApplicationBuilder
    .Create(TestConstants.ClientId)
    .WithClientSecret("secret")
    .WithLogging(myLogger, enablePiiLogging)
    .Build();

Logging in a distributed token cache

If you use token cache serializers from Microsoft.Identity.Web.TokenCache package on .NET, you can enable additional caching logs.

To enable distributed cache logging, set the MinLevel property to Debug.

     app.AddDistributedTokenCache(services =>
     {
          services.AddDistributedMemoryCache();
          services.AddLogging(configure => configure.AddConsole())
               .Configure<LoggerFilterOptions>(options => options.MinLevel = Microsoft.Extensions.Logging.LogLevel.Debug);
     });

See Implement a custom logging provider for more details.

Correlation ID

Logs help understand the MSAL behavior on the client side. To understand what's happening on the service side, the team needs a correlation ID. This ID traces an authentication request through the various backend services.

The correlation ID can be obtained in three ways:

  1. From a successful authentication result: AuthenticationResult.CorrelationId.
  2. From a service exception: MsalException.CorrelationId.
  3. By passing a custom correlation ID to WithCorrelationId(Guid) when building a token request.

When providing your own correlation ID, use a different ID value for each request. Don't use a constant as we won't be able to differentiate between the requests.

Network traces

Important

Network traces typically contain personally-identifiable information and credentials. Remove any sensitive details before posting the logs on GitHub.

In cases where verbose logs don't provide sufficient insights, you can get a network trace using tools like Fiddler or mitmproxy. You can configure your tool of choice to be a local proxy and accept traffic from devices on your local network, allowing you to capture traces from other devices, such as iPhone or Android phones. Platform-specific configuration may be required prior to capturing logs.

If such tool is not possible to use, you can modify the HttpClient used by MSAL to log the HTTP traffic. For reference, see this custom HttpClient implementation with logging.

Warning

This client should not be used in production and only for logging.

Custom HttpClient can be added like this:

var msalPublicClient = PublicClientApplicationBuilder
       .Create(ClientId)
       .WithHttpClientFactory(new HttpSnifferClientFactory())
       .Build();

Network traces when using WAM

To collect network traces for Web Account Manager (WAM) on Windows with Fiddler, a few extra steps are needed.

  1. Enable AppContainer loopback in Fiddler by clicking on WinConfig, selecting Exempt All and saving the changes.

Exemption interface in Fiddler, showing all applications in the WinConfig dialog.

  1. Enable HTTPS decryption, but exclude ADFS (msft.sts.microsoft.com) from HTTPS decryption:

Screenshot of Fiddler Options, showing how to configure HTTPS decryption