ASP.NET Core - getting a message back from AuthenticationHandler

Override HandleChallengeAsync:

In the example below the failReason is a private field in my implementation of AuthenticationHandler. I don't know if this is the best way to pass the reason for failure. But the AuthenticationProperties on the AuthenticateResult.Fail method did not make it through to HandleChallengeAsync in my test.

public class CustomAuthenticationHandler<TOptions> : AuthenticationHandler<TOptions> where TOptions : AuthenticationSchemeOptions, new()
{
    private string failReason;

    public CustomAuthenticationHandler(IOptionsMonitor<TOptions> options
        , ILoggerFactory logger
        , UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock) { }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        failReason = "Reason for auth fail";
        return AuthenticateResult.Fail(failReason);
    }

    protected override Task HandleChallengeAsync(AuthenticationProperties properties)
    {
        Response.StatusCode = 401;

        if (failReason != null)
        {
            Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = failReason;
        }

        return Task.CompletedTask;
    }
}

From the docs: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationhandler-1?view=aspnetcore-2.2

Override this method to deal with 401 challenge concerns, if an authentication scheme in question deals an authentication interaction as part of it's request flow. (like adding a response header, or changing the 401 result to 302 of a login page or external sign-in location.)

Source: https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication/AuthenticationHandler.cs#L201