How to log "unauthorized" (401) response

Viewed 1529

I'm using JWT tokens for authentication

services.AddAuthentication(options =>
{
    options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
    .AddJwtBearer(jwtOptions =>
    {
        jwtOptions.TokenValidationParameters = tokenValidationParameters;
    });

In my controller then the [Authorize] attribute is used to ensure caller needs to be authenticated. This works fine.

However: If a unauthorized user makes a request he gets a 401 response. Can I somehow "interupt" this response and log that an unauthorized call was made?

EDIT

A suggestion was to add an "exception middleware" I did so already but an unautorized call does not throw an exception...

services.AddMvc()
    .AddMvcOptions(options =>
    {
        // Order is important! A request will run from top to bottom through each filter.
        options.Filters.Add(typeof(MyExceptionFilterAttribute));
    });

and the attribute:

public class MyExceptionFilterAttribute : ExceptionFilterAttribute
{
    /// <summary>
    /// ctor
    /// </summary>
    public MyExceptionFilterAttribute()
    {

    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(ExceptionContext context)
    {


        ApplicationLogger.LogError("Bad request", context.Exception);
    }
}
2 Answers

How about this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
    // ...

    app.Use(async (context, next) =>
    {
        await next();

        if (context.Response.StatusCode == (int)System.Net.HttpStatusCode.Unauthorized)
        {
            logger.LogWarning("Unauthorized request");
        }
    });

    app.UseAuthentication();

    // ...
}

You can register a handler on failed authentication events:

var builder = services.AddAuthentication(options => { ... });
builder.AddJwtBearer(options =>
{
    var logger = services.BuildServiceProvider().GetRequiredService<ILogger<JwtBearerHandler>>();

    options.Events = new JwtBearerEvents
    {
         OnAuthenticationFailed = context =>
         {
             logger.LogWarning(context.Exception, "Unauthorized request.");
             return Task.CompletedTask;
         },
     };
});

The exception contains all the details what went wrong during authentication, e.g. invalid token, invalid audience, lifetime expired etc.

Related