{"id":9152,"date":"2022-10-12T05:23:18","date_gmt":"2022-10-12T05:23:18","guid":{"rendered":"https:\/\/blogs.aaddevsup.xyz\/?p=9152"},"modified":"2022-10-12T19:30:51","modified_gmt":"2022-10-12T19:30:51","slug":"use-logging-to-troubleshoot-azure-ad-protected-web-api-authentication-or-authorization-errors","status":"publish","type":"post","link":"https:\/\/blogs.aaddevsup.xyz\/2022\/10\/use-logging-to-troubleshoot-azure-ad-protected-web-api-authentication-or-authorization-errors\/","title":{"rendered":"Use logging to troubleshoot Azure AD protected Web API Authentication or Authorization errors"},"content":{"rendered":"\n

The sample web API application in this blog uses .Net 6 Framework and Microsoft.Identity.Web<\/a> nuget package to Azure AD protect the Web API. I use Serilog<\/a> framework for logging the debug output both to the console window and to the local file. This sample assumes you already have a web API application registered in Azure AD. If you are not familiar with how to do that refer to my previous<\/a> blog on the same web API protection topic. To troubleshoot web API Authentication\/Authorization issues, we can take advantage of the following JWTBearerEvents<\/a> to get insight into why a JWT Bearer token might fail to validate: OnTokenValidated, OnMessageReceived, OnAuthenticationFailed, and OnChalleenge events.<\/p>\n\n\n\n

Here is how I configure the App ID URI for my Web API<\/p>\n\n\n\n

\"\"<\/figure>\n\n\n\n

You can find the source code for this project on github<\/a>. Below is my Program.cs file showing how to set up logging for the above events:<\/p>\n\n\n\n

using Microsoft.AspNetCore.Authentication;\nusing Microsoft.AspNetCore.Authentication.JwtBearer;\nusing Microsoft.Identity.Web;\nusing Microsoft.IdentityModel.Logging;\nusing System.Diagnostics;\nusing Serilog;\n\n\n\/\/ https:\/\/github.com\/datalust\/dotnet6-serilog-example\n\nLog.Logger = new LoggerConfiguration()\n    .WriteTo.Console()\n    .CreateBootstrapLogger();\n\nLog.Information(\"starting up\");\ntry\n{\n    var builder = WebApplication.CreateBuilder(args);\n\n    builder.Host.UseSerilog((ctx, lc) => lc\n        .WriteTo.Console()\n        .ReadFrom.Configuration(ctx.Configuration));\n\n    \/\/ Add services to the container.\n    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\n        .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection(\"AzureAd\"));\n\n    \/\/ Enable PII for logging\n    IdentityModelEventSource.ShowPII = true;\n    \/\/ Configure middleware events\n    builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>\n    {\n        options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters\n        {\n            ValidAudiences = new List<string> { \"api:\/\/a56797c4-e6f7-4d8c-89cc-0b3cc64d8b3e\", \"a56797c4-e6f7-4d8c-89cc-0b3cc64d8b3e\" },\n            ValidIssuers = new List<string> { \"https:\/\/sts.windows.net\/<tenant ID>\/\", \"https:\/\/login.microsoftonline.com\/<tenant ID>\/v2.0\" }\n        };\n        options.Events = new JwtBearerEvents\n        {\n            OnTokenValidated = ctx =>\n            {\n                string message = \"[OnTokenValidated]: \";\n                message += $\"token: {ctx.SecurityToken.ToString()}\";\n                Log.Information(message); \n                return Task.CompletedTask;\n            },\n            OnMessageReceived = ctx =>\n            {\n                string message = \"[OnMessageReceived]: \";\n                ctx.Request.Headers.TryGetValue(\"Authorization\", out var BearerToken);\n                if (BearerToken.Count == 0)\n                    BearerToken = \"no Bearer token sent\\n\";\n                message += \"Authorization Header sent: \" + BearerToken + \"\\n\";\n                Log.Information(message);\n                return Task.CompletedTask;\n            },\n            OnAuthenticationFailed = ctx =>\n            {\n                ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;\n                string message = $\"[OnAuthenticationFailed]: {ctx.Exception.ToString()}\";\n                Log.Error(message);\n                \/\/ Debug.WriteLine(\"[OnAuthenticationFailed]: Authentication failed with the following error: \");\n                \/\/ Debug.WriteLine(ctx.Exception);\n                return Task.CompletedTask;\n            },\n            OnChallenge = ctx =>\n            {\n                \/\/ Debug.WriteLine(\"[OnChallenge]: I can do stuff here! \");\n                Log.Information(\"[OnChallenge]\");\n                return Task.CompletedTask;\n            },\n            OnForbidden = ctx =>\n            {\n                Log.Information(\"[OnForbidden]\");\n                return Task.CompletedTask;\n            }\n        };\n    });\n\n    builder.Services.AddControllers();\n    \/\/ Learn more about configuring Swagger\/OpenAPI at https:\/\/aka.ms\/aspnetcore\/swashbuckle\n    \/\/ builder.Services.AddEndpointsApiExplorer();\n    \/\/ builder.Services.AddSwaggerGen();\n\n    var app = builder.Build();\n\n    app.UseSerilogRequestLogging();\n    \/\/ Configure the HTTP request pipeline.\n    if (app.Environment.IsDevelopment())\n    {\n        \/\/ app.UseSwagger();\n        \/\/ app.UseSwaggerUI();\n        \/\/ do something\n    }\n\n    app.UseHttpsRedirection();\n\n    app.UseAuthentication();\n    app.UseAuthorization();\n\n    app.MapControllers();\n\n    app.Run();\n}\ncatch (Exception ex)\n{\n    Log.Fatal(ex, \"Unhandled exception\");\n}\nfinally\n{\n    Log.Information(\"Shut down complete\");\n    Log.CloseAndFlush();\n}\n<\/pre>\n\n\n\n

To run this sample change the following section with your own app registration info: <\/p>\n\n\n\n

  • the AzureAD section in appsettings.json file<\/li>
  • TokenValidationParameters’s ValidAudiences and ValidIssuers in Program.cs<\/li><\/ul>\n\n\n\n

    The sample writes log output to both a console window and local file whose path is specified in appsettings.json<\/p>\n","protected":false},"excerpt":{"rendered":"

    The sample web API application in this blog uses .Net 6 Framework and Microsoft.Identity.Web nuget package to Azure AD protect the Web API. I use Serilog framework for logging the debug output both to the console window and to the local file. This sample assumes you already have a web API application registered in Azure AD. If you are not familiar with how to do that refer to my previous…<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3,5],"tags":[240,165,137],"class_list":["post-9152","post","type-post","status-publish","format-standard","hentry","category-app-registration","category-authentication","category-azure-ad","tag-asp-net-core","tag-microsoft-identity-web","tag-web-appapi"],"_links":{"self":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts\/9152"}],"collection":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/comments?post=9152"}],"version-history":[{"count":9,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts\/9152\/revisions"}],"predecessor-version":[{"id":9165,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/posts\/9152\/revisions\/9165"}],"wp:attachment":[{"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/media?parent=9152"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/categories?post=9152"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.aaddevsup.xyz\/wp-json\/wp\/v2\/tags?post=9152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}