7

I have a .NET Core 2.0 application using OAuth Bearer Auth with an Azure AD V2 endpoint. I want to the exception message to be returned to the user if there is a 500 error. I have the following code to do that:

            options.Events = new JwtBearerEvents
            {
                // This used to be options.Notifications = new OpenIdConnectAuthenticationNotifications
                OnTokenValidated = AzureAdAuthCallbacks.TokenValidated,
                OnAuthenticationFailed = async context =>
                {
                    context.Response.ContentType = "text/plain";
                    await context.Response.WriteAsync(context.Exception.Message);
                }
            };
        }

When validation fails, that code does execute, but the response dosn't get returned. I get a stack trace.

This is the message:

System.InvalidOperationException: StatusCode cannot be set because the response has already started.

With this line of note:

at WebCsProj.Infrastructure.RequestMetadataMiddelware.<>c.<b__0_0>d.MoveNext() in C:\Users\justin.dearing\source\repos\my-solution\WebCsProj\Infrastructure\RequestMetadataMiddelware.cs:line XXX

However, that piece of middleware finishes successfully:

public static class RequestMetadataMiddelware
{
    public static IApplicationBuilder UseRequestMetadataExtractor(this IApplicationBuilder app)
    {
        return app.Use(async (context, next) =>
        {
            // I don't set a status code here.
            // Some code that works is here
            await next.Invoke(); // The debugger indicates the code makes it here:
        });
    }
}

What can I do to debug this or what is the right way to set the response? Is there a way to stop the middle-ware chain from executing in OnAuthenticationFailed?

Justin Dearing
  • 14,270
  • 22
  • 88
  • 161
  • Error message is pretty clear. Some other middleware in the pipeline has already started writing to the response body. This means, that the headers have already been sent and you can't set them again. Its how HTTP work, headers must be sent before the content comes. Once the content is being written, no additional headers may be added – Tseng Mar 28 '18 at 14:34
  • @Tseng error message is clear but unhelpful. I know some piece of middleware (one I didn't write or have the source code to) is writing to the response. I know explicitly its not the one I did write. – Justin Dearing Mar 28 '18 at 15:33
  • 1
    This doesn't work in 2.0, there's a bug about it in the security repo. – Tratcher Mar 28 '18 at 15:36
  • https://github.com/aspnet/Security/issues/1680 – Tratcher Mar 28 '18 at 15:40
  • @tratcher the answer below worked. – Justin Dearing Mar 28 '18 at 22:39
  • 1
    JwtBearer doesn't control the request flow, it's not possible to send a response. The answer below causes response corruption. – Tratcher Mar 28 '18 at 23:56
  • Does this answer your question? [AddJwtBearer OnAuthenticationFailed return custom error](https://stackoverflow.com/questions/48649717/addjwtbearer-onauthenticationfailed-return-custom-error) – Michael Freidgeim Feb 04 '23 at 02:58

1 Answers1

5

You can write the response body after invoking the next middleware using OnStarting method:

OnAuthenticationFailed = context =>
{
    context.Response.OnStarting(async () =>
    {
        context.Response.ContentType = "text/plain";
        await context.Response.WriteAsync(context.Exception.Message);
    });

    return Task.CompletedTask;
}
Andriy Tolstoy
  • 5,690
  • 2
  • 31
  • 30
  • 1
    Never write to the body in OnStarting, you're corrupting the response. Expect multiple errors to be logged. – Tratcher Mar 28 '18 at 23:53
  • 1
    @Tratcher is `await context.Response.WriteAsync(context.Exception.Message);` the part you are referring to, that should not happen during OnStarting? – petrosmm Nov 03 '20 at 19:45
  • That's Correct. – Tratcher Nov 03 '20 at 22:06
  • You don’t need OnStarting. See similar answers https://stackoverflow.com/questions/48649717/addjwtbearer-onauthenticationfailed-return-custom-error/50451116#50451116 and https://stackoverflow.com/questions/66619766/authorizeattribute-return-custom-value-in-asp-net-core-without-override/66620044#66620044. Please UPDATE the answer. As was [pointed by Tratcher](https://stackoverflow.com/questions/49537061/sending-response-body-in-jwtbearerevents-onauthenticationfailed/49538649#comment86099347_49538649) “ multiple errors to be logged” – Michael Freidgeim Feb 04 '23 at 02:36