'Include custom WWW-Authenticate header in 401 Unauthorised response when using Microsoft.Identity.Web

Following instructions on making MS Office connect to my Asp.NET Core Web API, I am attempting to present a login redirect to MS Office for failed authentications. Following questions and answers I am attempting to include the login redirect information in the WWW-Authenticate header property. My Web API is protected with Azure AD and the Microsoft.Identity.Web library. When the authentication fails and the middleware returns the 401 Unauthorized response, the header does include the WWW-Authenticate property but it's value is only Bearer.

Q: How can update the header information to include the necessary additional redirect information?

I have tried to implement an attribute on the API, derived from IAsyncAuthorizationFilter and access the response header in that. However the middleware already returns a 401 before this attribute is called.



Solution 1:[1]

I have made progress by customizing the JwtBearerOptions configuration. However this approach creates an additional header item, instead of overwriting the standard value. As a result I have now 2 KeyValuePairs for the same key in the response header, which will likely have unexpected outcomes.

In my Startup.cs:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration)

services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    var existingOnChallengeHandler = options.Events.OnChallenge;
    options.Events.OnChallenge = async context =>
    {
        await existingOnChallengeHandler(context);

        string headerInfo = context.Options.Challenge;
        headerInfo += " resource=\"https://management.azure.com/\"";
        context.Response.Headers.Append(HeaderNames.WWWAuthenticate, headerInfo);
    };
});

Solution 2:[2]

The original answer put me on the right track. It turned out to be actually quite simple to do this once I knew to configure the JwtBearerOptions.Challenge property:

services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.Challenge = $"Bearer authorization_uri=\"{authorizationUri}\"";
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Lars Kemmann