Skip to content

Commit 25c2bf2

Browse files
author
Simonx Xu
authored
Merge pull request #8818 from AmandaAZ/Branch-CI5500
AB#5500: Convert blog post to article
2 parents e6c16b3 + 31a1a0a commit 25c2bf2

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed
261 KB
Loading
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
title: Use Serilog to Troubleshoot Protected Web API Authentication or Authorization Errors
3+
description: Provides a sample web API application to troubleshoot Microsoft Entra protected Web API authentication or authorization errors using Serilog logs.
4+
ms.date: 05/12/2025
5+
ms.service: entra-id
6+
ms.custom: sap:Developing or Registering apps with Microsoft identity platform
7+
ms.reviewer: bachoang, v-weizhu
8+
---
9+
# Use Serilog to troubleshoot Microsoft Entra protected Web API authentication or authorization errors
10+
11+
When a web API application calls a web API that's protected with Microsoft Entra ID, authentication or authorization errors might occur due to JwtBearer event validation failures. To troubleshoot this issue, this article introduces a sample web API application named [Net6WebAPILogging](https://github.com/bachoang/Net6WebAPILogging) to set and collect logs for JwtBearer events.
12+
13+
## Net6WebAPILogging sample application
14+
15+
This sample web API application assumes you already have a web API registered in Microsoft Entra ID. It uses Microsoft .NET 6 Framework and [Microsoft Identity Web](/entra/msal/dotnet/microsoft-identity-web/) NuGet package.
16+
17+
It uses the following methods to set and collect logs for JwtBearer events:
18+
19+
- Use the [JwtBearerEvents class](/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbearerevents) to configure middleware events. JWT Bearer token might fail to validate `OnTokenValidated`, `OnMessageReceived`, `OnAuthenticationFailed`, and `OnChalleenge` events.
20+
- [Set up logging for JwtBearer events](#set-up-logging-for-jwtbearer-events).
21+
- Use the [Serilog](https://serilog.net/) framework to log the `Debug` output to the console window and the local file whose path is specified in the **appsettings.json** file.
22+
23+
## Run the sample application
24+
25+
To run the sample application, you must perform the following steps:
26+
27+
### Step 1: Configure the application ID URI for a protected web API
28+
29+
To add the application ID URI for a web API, follow these steps:
30+
31+
1. In the Azure portal, navigate to the app registration of the web API.
32+
2. Select **Expose an API** under **Manage**.
33+
3. At the top of the page, select **Add** next to **Application ID URI**. The default is `api://<application-client-id>`.
34+
35+
:::image type="content" source="media/serilog-protected-web-api-authentication-authorization-errors/application-id-uri.png" alt-text="Screenshot that shows how to set the application ID URI in an app registration.":::
36+
5. Select **Save**.
37+
38+
### Step 2: Change the sample application configuration
39+
40+
Change the following information in the `AzureAd` section in the **appsettings.json** file with your own app registration information:
41+
42+
```json
43+
"AzureAd": {
44+
"Instance": "https://login.microsoftonline.com/",
45+
"Domain": "<tenant name>.onmicrosoft.com", // for example contoso.onmicrosoft.com
46+
"TenantId": "<tenant ID>",
47+
"ClientId": "<application-client-id>"
48+
},
49+
```
50+
51+
### Step 3: Change the sample application code
52+
53+
Change the `ValidAudiences` and `ValidIssuers` properties of the [TokenValidationParameters](/dotnet/api/microsoft.identitymodel.tokens.tokenvalidationparameters) class in the **Program.cs** file.
54+
55+
### Step 4: Configure Serilog
56+
57+
Configure Serilog in the `Serilog` section in the **appsettings.json** file as follows:
58+
59+
```json
60+
"Serilog": {
61+
"MinimumLevel": {
62+
"Default": "Information",
63+
"Override": {
64+
"Microsoft": "Debug",
65+
"Microsoft.Hosting.Lifetime": "Information"
66+
}
67+
},
68+
```
69+
70+
## Set up logging for JwtBearer events
71+
72+
Here's the sample **Program.cs** file that shows how to set up logging for the preceding events:
73+
74+
```csharp
75+
using Microsoft.AspNetCore.Authentication;
76+
using Microsoft.AspNetCore.Authentication.JwtBearer;
77+
using Microsoft.Identity.Web;
78+
using Microsoft.IdentityModel.Logging;
79+
using System.Diagnostics;
80+
using Serilog;
81+
82+
83+
// https://github.com/datalust/dotnet6-serilog-example
84+
85+
Log.Logger = new LoggerConfiguration()
86+
.WriteTo.Console()
87+
.CreateBootstrapLogger();
88+
89+
Log.Information("starting up");
90+
try
91+
{
92+
var builder = WebApplication.CreateBuilder(args);
93+
94+
builder.Host.UseSerilog((ctx, lc) => lc
95+
.WriteTo.Console()
96+
.ReadFrom.Configuration(ctx.Configuration));
97+
98+
// Add services to the container.
99+
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
100+
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
101+
102+
// Enable PII for logging
103+
IdentityModelEventSource.ShowPII = true;
104+
// Configure middleware events
105+
builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
106+
{
107+
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
108+
{
109+
ValidAudiences = new List<string> { "api://<application-client-id>", "<application-client-id>" },
110+
ValidIssuers = new List<string> { "https://sts.windows.net/<tenant ID>/", "https://login.microsoftonline.com/<tenant ID>/v2.0" }
111+
};
112+
options.Events = new JwtBearerEvents
113+
{
114+
OnTokenValidated = ctx =>
115+
{
116+
string message = "[OnTokenValidated]: ";
117+
message += $"token: {ctx.SecurityToken.ToString()}";
118+
Log.Information(message);
119+
return Task.CompletedTask;
120+
},
121+
OnMessageReceived = ctx =>
122+
{
123+
string message = "[OnMessageReceived]: ";
124+
ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken);
125+
if (BearerToken.Count == 0)
126+
BearerToken = "no Bearer token sent\n";
127+
message += "Authorization Header sent: " + BearerToken + "\n";
128+
Log.Information(message);
129+
return Task.CompletedTask;
130+
},
131+
OnAuthenticationFailed = ctx =>
132+
{
133+
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
134+
string message = $"[OnAuthenticationFailed]: {ctx.Exception.ToString()}";
135+
Log.Error(message);
136+
// Debug.WriteLine("[OnAuthenticationFailed]: Authentication failed with the following error: ");
137+
// Debug.WriteLine(ctx.Exception);
138+
return Task.CompletedTask;
139+
},
140+
OnChallenge = ctx =>
141+
{
142+
// Debug.WriteLine("[OnChallenge]: I can do stuff here! ");
143+
Log.Information("[OnChallenge]");
144+
return Task.CompletedTask;
145+
},
146+
OnForbidden = ctx =>
147+
{
148+
Log.Information("[OnForbidden]");
149+
return Task.CompletedTask;
150+
}
151+
};
152+
});
153+
154+
builder.Services.AddControllers();
155+
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
156+
// builder.Services.AddEndpointsApiExplorer();
157+
// builder.Services.AddSwaggerGen();
158+
159+
var app = builder.Build();
160+
161+
app.UseSerilogRequestLogging();
162+
// Configure the HTTP request pipeline.
163+
if (app.Environment.IsDevelopment())
164+
{
165+
// app.UseSwagger();
166+
// app.UseSwaggerUI();
167+
// do something
168+
}
169+
170+
app.UseHttpsRedirection();
171+
172+
app.UseAuthentication();
173+
app.UseAuthorization();
174+
175+
app.MapControllers();
176+
177+
app.Run();
178+
}
179+
catch (Exception ex)
180+
{
181+
Log.Fatal(ex, "Unhandled exception");
182+
}
183+
finally
184+
{
185+
Log.Information("Shut down complete");
186+
Log.CloseAndFlush();
187+
}
188+
```
189+
190+
## References
191+
192+
[Tutorial: Build and secure an ASP.NET Core web API with the Microsoft identity platform](/entra/identity-platform/tutorial-web-api-dotnet-core-build-app)
193+
194+
[!INCLUDE [Azure Help Support](../../../includes/third-party-disclaimer.md)]
195+
196+
[!INCLUDE [Azure Help Support](../../../includes/azure-help-support.md)]

support/entra/entra-id/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@
6969
href: app-integration/package-inspector-msal-android-native.md
7070
- name: Repeated login prompts in iOS MSAL implementation
7171
href: app-integration/repeat-login-prompts-in-msal-ios-app.md
72+
- name: Troubleshoot protected Web API authentication or authorization errors with Serilog
73+
href: app-integration/serilog-protected-web-api-authentication-authorization-errors.md
7274
- name: WIF10201 No valid key mapping found
7375
href: app-integration/troubleshoot-wif10201-no-validkey-securitytoken-mvc.md
7476

0 commit comments

Comments
 (0)