I have a .Net 5 Web API that is protected by Azure AD. What I want to accomplish is to provide custom error message when authorization fails. For example,
- If a user forgets to add
Authorization
header in the request, I want to tell the user that this header is required. - If the token has expired, I want to tell the user exactly that rather than simply returning
401
status code with no details.
Simply putting [Authorize]
attribute before controller and/or action does not work as it returns 401
status code and does not include any details about this error.
I searched for it and found that I have to write a custom authorization filter and using that it should be possible to accomplish what I am looking for.
Using this blog post
, I was able to write a custom authorization filter however I am still not able to find out how to validate the token and return appropriate error messages.
Here's the code I wrote so far:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
AuthorizationPolicy policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
_ = services.AddAuthorization(options =>
{
options.DefaultPolicy = policy;
});
_ = services.AddControllers(options =>
{
options.Filters.Add(new CustomTokenAuthorizationFilter(policy));
});
_ = services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
});
_ = services
.AddMicrosoftIdentityWebApiAuthentication(Configuration, "ApiSettings");
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
_ = app.UseDeveloperExceptionPage();
_ = app.UseSwagger();
_ = app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API v1"));
}
_ = app.UseConfigureRequestHeaders();
_ = app.UseHttpsRedirection();
_ = app.UseRouting();
//_ = app.UseAuthentication();
_ = app.UseAuthorization();
_ = app.UseEndpoints(endpoints =>
{
_ = endpoints.MapControllers();
});
}
}
CustomAuthorizationFilter.cs
public class CustomTokenAuthorizationFilter : AuthorizeFilter
{
public CustomTokenAuthorizationFilter(AuthorizationPolicy policy) : base(policy)
{
}
public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// Allow Anonymous skips all authorization
if (context.Filters.Any(item => item is IAllowAnonymousFilter))
{
return;
}
var policyEvaluator = context.HttpContext.RequestServices.GetRequiredService<IPolicyEvaluator>();
var authenticateResult = await policyEvaluator.AuthenticateAsync(Policy, context.HttpContext);
var authorizeResult = await policyEvaluator.AuthorizeAsync(Policy, authenticateResult, context.HttpContext, context);
return;
}
}
With this code, when there's an issue with my token authenticateResult.Succeeded
property is false
and authorizeResult.Challenged
property is true
.
How can I find out what caused the authorization to fail? Any help would be highly appreciated.
I am using Microsoft.Identity.Web
NuGet Package as suggested by Microsoft.
What you could possibly do here and user an error controller and catch your unauthorized exception and then output the message from that exception.
This is a good Stackoverflow post about how to configure an error controller