ASP.NET Core 3.1 - AddJwtBearer, OnTokenValidated event not respecting custom message on Fail

Viewed 1196

I have a scenario where I need to recreate the principal if a bearer token is provided in the request. For this I use the OnTokenValidated event to execute some custom logic (if bearer is valid). I check if the user email is verified, if so I add custom claims to the user identity which I can then access later on during the same request and make use of the authorisation attributes on controllers and actions.

However I'm trying to return a custom message if the email is not verified, but I keep getting "Unauthorised" back, even though this code is being hit and using the preferred message.

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.Authority = customDomain;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateAudience = true,
                    ValidAudiences = audiences,
                    ValidateIssuer = true,
                    ValidIssuers = issuers
                };

                options.Events = new JwtBearerEvents
                {
                    OnTokenValidated = async (context) =>
                    {
                        var user = context.Principal;

                        //Check if already restored during current request
                        if (user.GetDefaultUserPrincipal() == null)
                        {
                            var securityManager = context.HttpContext.RequestServices.GetRequiredService<ISecurityManager>();
                            var authResponse = await securityManager.AuthenticateMarketplaceFromBearerRequestAsync(user);

                            if(!authResponse.IsAuthenticated)
                            {
                                context.Fail(authResponse.Message);
                            }
                        }
                    }
                };
            });

Am I missing something here? I've also tried throwing an exception and handling that response in the AuthenticationFailed event, but I get the same thing.

Alternatively I'm playing with the idea of creating a custom policy to do this check as long I can still return a custom response message.

1 Answers

In order to display your custom message when failing the authentication, you can write it to the response of the AuthenticationFailedContext context object.

...

if (!authResponse.IsAuthenticated){
  // set the content-type of the response
  context.Response.ContentType = "application/json";

  // prepare your custom data
  var data = new { MyCustomMessage = authResponse.Message };

  // user serializer to form your data to string. Here I used Newtonsoft.Json
  var jsonResult = JsonConvert.SerializeObject(data);

  // Write the jsonresult to the response. Make sure this returns a Task
  context.Response.WriteAsync(jsonResult);
}

...
Related