|
| 1 | +--- |
| 2 | +title: Enable Logging for MSAL.NET and Microsoft Graph SDK |
| 3 | +description: Introduces how to enable logging for both MSAL.NET and Microsoft Graph SDK. |
| 4 | +ms.reviewer: bachoang, v-weizhu |
| 5 | +ms.service: entra-id |
| 6 | +ms.date: 07/16/2025 |
| 7 | +ms.custom: sap:Problem with using the Graph SDK - libraries |
| 8 | +ms.topic: how-to |
| 9 | +--- |
| 10 | +# How to enable logging for MSAL.NET and Microsoft Graph SDK |
| 11 | + |
| 12 | +[Microsoft Graph SDK](/graph/sdks/sdks-overview) has the ability to log complete HTTP requests and responses. The way this logging mechanism works is by implementing a custom [HttpClient Message handler](https://visualstudiomagazine.com/articles/2014/08/01/creating-custom-httpclient-handlers.aspx) to intercept every HTTP request and response between the client application and the Microsoft Graph Service. Besides hooking into the processing pipeline of the `GraphServiceClient` class to do request and response tracing, you can also configure proxy information. For more information, see [Customize the Microsoft Graph SDK service client](/graph/sdks/customize-client?tabs=csharp). MSAL.NET is used in the authentication provider of the `GraphServiceClient` class. Consequently, [logging](/azure/active-directory/develop/msal-logging-dotnet) in this library can provide valuable insight into authentication failures. |
| 13 | + |
| 14 | +This article explains how to enable logging for both MSAL.NET and Microsoft Graph SDK by using a [.NET Core 3.0 console application sample](https://github.com/bachoang/MSGraphLoggingSample). |
| 15 | + |
| 16 | +## Logging techniques |
| 17 | + |
| 18 | +Different logging approaches are used to write log entries to Azure Blob Storage for MSAL.NET logging and Microsoft Graph SDK logging. The logging mechanisms provide insights into HTTP requests and responses, as well as authentication failures, which are invaluable for debugging and troubleshooting. |
| 19 | + |
| 20 | +### MSAL.NET logging |
| 21 | + |
| 22 | +For MSAL.NET logging, the [Azure Blob Storage client SDK](/azure/storage/blobs/storage-quickstart-blobs-dotnet) (v12) is used to write log entries into an Azure Blob. |
| 23 | + |
| 24 | +### Microsoft Graph SDK logging |
| 25 | + |
| 26 | +For Microsoft Graph SDK logging, the [Serilog](https://serilog.net/) library is used. Serilog offers various logging providers, known as "sinks," that support different logging environments such as Application Insight, DocumentDB, and Event Hubs. |
| 27 | + |
| 28 | +In the following code, three logging sinks are configured: console logger, file logger, and Azure Blob Storage logger. You don't have to use all three and can add new one(s) or comment out the providers you don't need. |
| 29 | + |
| 30 | +```csharp |
| 31 | +Log.Logger = new LoggerConfiguration() |
| 32 | +.MinimumLevel.Debug() |
| 33 | +.WriteTo.Console() // Serilog console logging |
| 34 | +.WriteTo.File(LoggingLocalPath, rollingInterval: RollingInterval.Day) // Serilog file logging |
| 35 | +.WriteTo.AzureBlobStorage(AzureStorageConnection, Serilog.Events.LogEventLevel.Verbose, MSGraphAzureBlobContainerName, MSGraphAzureBlobName) // Serilog Azure Blob Storage logging |
| 36 | +.CreateLogger(); |
| 37 | +``` |
| 38 | + |
| 39 | +> [!NOTE] |
| 40 | +> When the Serilog Azure Blob Storage sink is used for both MSAL.NET and Microsoft Graph SDK logging, you might encounter an authentication issue where the authentication prompt window fails to appear. |
| 41 | +
|
| 42 | +## Prerequisites for running the sample application |
| 43 | + |
| 44 | +Before running the sample application, ensure the following prerequisites are met. |
| 45 | + |
| 46 | +### Application registration |
| 47 | + |
| 48 | +1. Register the sample application in Microsoft Entra ID. |
| 49 | + |
| 50 | + During the application registration, configure `http://localhost` as a redirect URI under the **Mobile and desktop applications** platform. This URI is required for .NET Core applications. |
| 51 | + |
| 52 | + :::image type="content" source="media/enable-logging-for-msal-and-microsoft-graph/set-redirect-uri.png" alt-text="Screenshot that shows setting a redirect URI"::: |
| 53 | + |
| 54 | +2. Configure these delegated Microsoft Graph permissions in **API permissions**: |
| 55 | + |
| 56 | + - **User.Read.All** |
| 57 | + - **Application.ReadWrite.All** |
| 58 | + |
| 59 | +3. Grant admin consent to these permissions because the sample application uses the following Microsoft Graph requests to get the signed-in user information and create an app registration: |
| 60 | + |
| 61 | + - `GET https://graph.microsoft.com/beta/me` |
| 62 | + - `POST https://graph.microsoft.com/beta/applications` |
| 63 | + |
| 64 | +> [!NOTE] |
| 65 | +> Ensure the signed-in user has one of these administrative roles: Application Developer, Application Administrator, Cloud Application Administrator, or Global Administrator; otherwise, the application creation might fail due to insufficient permissions. For a list of built-in Microsoft Entra roles, see [Microsoft Entra built-in roles](/entra/identity/role-based-access-control/permissions-reference) . |
| 66 | +
|
| 67 | +### Azure Storage |
| 68 | + |
| 69 | +Create an Azure Storage account for storing MSAL.NET and Microsoft Graph SDK logs as Azure Blobs. For read/write access to Azure Storage, you can use a connection string in **Key 1** or **Key 2** under **Access keys**. |
| 70 | + |
| 71 | +:::image type="content" source="media/enable-logging-for-msal-and-microsoft-graph/connection-string-under-access-keys.png" alt-text="Screenshot that shows connection strings under 'Access keys'"::: |
| 72 | + |
| 73 | +### Application code |
| 74 | + |
| 75 | +The complete sample code is available in this [GitHub repository](https://github.com/bachoang/MSGraphLoggingSample). Configuration options are stored in the following `appsettings.json` file. The sample application uses a code snippet from [this article](../app-integration/get-signed-in-users-groups-in-access-token.md) to read configuration settings from the `appsettings.json` file. It relies on the Microsoft Graph beta endpoint, so it references the Microsoft.Graph.Beta package; for v1 endpoint, use the Microsoft.Graph package. For more information, see [Use the Microsoft Graph SDKs with the beta API](/graph/sdks/use-beta). |
| 76 | + |
| 77 | +```json |
| 78 | +{ |
| 79 | + "Azure": { |
| 80 | + "ClientId": "", |
| 81 | + "TenantId": "", |
| 82 | + "MSALAzureBlobContainerName": "msallogs", |
| 83 | + "MSALAzureBlobName": "MsalLog.txt", |
| 84 | + "MSGraphAzureBlobContainerName": "msgraphlogs", |
| 85 | + "MSGraphAzureBlobName": "{yyyy}-{MM}-{dd}-msgraphlog.txt", |
| 86 | + "LoggingLocalPath": "C:/temp/msgraphlog.txt", |
| 87 | + "AzureStorageConnection": "", |
| 88 | + "Scopes": [ "https://graph.microsoft.com/.default" ] |
| 89 | + } |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +The sample application uses both `GET` and `POST` requests to show logging of the complete HTTP requests and responses, including headers and body. The following four helper functions are used to get the information for each part. Any function can be commented out if the corresponding information isn't required. |
| 94 | + |
| 95 | +:::image type="content" source="media/enable-logging-for-msal-and-microsoft-graph/helper-functions.png" alt-text="Screenshot that shows four helper functions"::: |
| 96 | + |
| 97 | +These helper functions are used in the logging `HttpClient` message handler as shown here. Requests are logged before calling the `DelegatingHandler.SendAsync` method and responses are logged after the call. |
| 98 | + |
| 99 | +```csharp |
| 100 | +public class SeriLoggingHandler : DelegatingHandler |
| 101 | +{ |
| 102 | + protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage httpRequest, CancellationToken cancellationToken) |
| 103 | + { |
| 104 | + HttpResponseMessage response = null; |
| 105 | + try |
| 106 | + { |
| 107 | + Log.Information("sending Graph Request"); |
| 108 | + Log.Debug(GetRequestHeader(httpRequest)); |
| 109 | + Log.Debug(GetRequestBody(httpRequest)); |
| 110 | + response = await base.SendAsync(httpRequest, cancellationToken); |
| 111 | + Log.Information("Receiving Response:"); |
| 112 | + Log.Debug(GetResponseHeader(response)); |
| 113 | + Log.Debug(GetResponseBody(response)); |
| 114 | + } |
| 115 | + catch (Exception ex) |
| 116 | + { |
| 117 | + Log.Error(ex, "Something went wrong"); |
| 118 | + if (response.Content != null) |
| 119 | + { |
| 120 | + await response.Content.ReadAsByteArrayAsync();// Drain response content to free connections. |
| 121 | + } |
| 122 | + } |
| 123 | + return response; |
| 124 | + } |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +The following code shows how to set up the `GraphServcieClient` class to use the logging handler: |
| 129 | + |
| 130 | +```csharp |
| 131 | +IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder |
| 132 | + .Create(ClientId) |
| 133 | + .WithTenantId(TenantId) |
| 134 | + // Enable MSAL logging |
| 135 | + .WithLogging(MSALlogger, Microsoft.Identity.Client.LogLevel.Verbose, true) |
| 136 | + .WithRedirectUri("http://localhost") |
| 137 | + .Build(); |
| 138 | + |
| 139 | + InteractiveAuthenticationProvider authProvider = new InteractiveAuthenticationProvider(publicClientApplication, Scopes); |
| 140 | + |
| 141 | + // get the default list of handlers and add the logging handler to the list |
| 142 | + var handlers = GraphClientFactory.CreateDefaultHandlers(authProvider); |
| 143 | + |
| 144 | + // Remove Compression handler |
| 145 | + var compressionHandler = |
| 146 | + handlers.Where(h => h is CompressionHandler).FirstOrDefault(); |
| 147 | + handlers.Remove(compressionHandler); |
| 148 | + |
| 149 | + // Add SeriLog logger |
| 150 | + handlers.Add(new SeriLoggingHandler()); |
| 151 | + |
| 152 | + InitializeBlobStorageForMSAL().Wait(); |
| 153 | + |
| 154 | + var httpClient = GraphClientFactory.Create(handlers); |
| 155 | + GraphServiceClient graphClient = new GraphServiceClient(httpClient); |
| 156 | +``` |
| 157 | + |
| 158 | +> [!CAUTION] |
| 159 | +> This sample logs sensitive information, including Personally Identifying Information (PII) and access tokens. Be cautious when sharing debug logs. |
| 160 | +
|
| 161 | +## Check MSAL.NET and Microsoft Graph logs |
| 162 | + |
| 163 | +After you run the sample application, Microsoft Graph requests and responses should appear in: |
| 164 | + |
| 165 | +- The console window. |
| 166 | +- The directory location configured in the `appsettings.json` file. Log file names include the date, as shown here: |
| 167 | + |
| 168 | + :::image type="content" source="media/enable-logging-for-msal-and-microsoft-graph/local-microsoft-graph-logs.png" alt-text="Screenshot that shows local logs"::: |
| 169 | + |
| 170 | +For Azure Blob Storage logging, the logs are in the `msallogs` and `msgraphlogs` containers: |
| 171 | + |
| 172 | +:::image type="content" source="media/enable-logging-for-msal-and-microsoft-graph/azure-blob-storage-logs.png" alt-text="Screenshot that shows Azure Blob Storage logs"::: |
| 173 | + |
| 174 | +[!INCLUDE [Azure Help Support](../../../includes/azure-help-support.md)] |
0 commit comments