1

I am using the libraries Microsoft.AspNetCore.Http and Microsoft.AspNetCore.Mvc. I am also using Identity's JWT token.

When the token has expired, the API throws a http 401 error, and if the claims are wrong, it returns a http 403 error.

I need to be able to catch those two statues and wrap them in my uniform error message format

public class ErrorMessage
{
     public int httpStatus { get; set; }
     public string Header { get; set; } = "Error";
     public string Message { get; set; }
}

My Standard API format

[Authorize]
[HttpPost]
[Route("Logout")]
public async Task<IActionResult> Logout()
{
    try
    {
        ....
    }
    catch (Exception e)
    {
        _logger.LogError($"Error in {nameof(Login)}: {e}");
        return BadRequest(new ErrorMessage { httpStatus = 500, Message = e.Message });
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
nour
  • 143
  • 1
  • 7
  • 16
  • Those exceptions are thrown by other middlewares which execute before the controller action. So try catch wont work. In general, you will need to write a [middleware](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-6.0) and intercept the exception inside that. – Mat J Dec 03 '21 at 09:36
  • Does this answer your question? [AddJwtBearer OnAuthenticationFailed return custom error](https://stackoverflow.com/questions/48649717/addjwtbearer-onauthenticationfailed-return-custom-error) – Mat J Dec 03 '21 at 09:38

2 Answers2

5

As per Handle errors in ASP.NET Core, you can use UseStatusCodePages:

app.UseStatusCodePages(async statusCodeContext =>
{
    switch (statusCodeContext.HttpContext.Response.StatusCode)
    {
        case 401:
            statusCodeContext.HttpContext.Response.StatusCode = 400;
            await statusCodeContext.HttpContext.Response.WriteAsJsonAsync(new ErrorMessage { httpStatus = 500, Message = "some message" });
            break;
        case 403:
            statusCodeContext.HttpContext.Response.StatusCode = 400;
            await statusCodeContext.HttpContext.Response.WriteAsJsonAsync(new ErrorMessage { httpStatus = 500, Message = "some message" });
            break;
    }
});
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
1

You can accomplish this by adding the following to the Configure method in your Startup.cs

This will let you intercept and change aspects of the response as well as the content type. In the below example, we're returning a simple JSON object with a Message.

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

    if (context.Response.StatusCode == (int)HttpStatusCode.Unauthorized) // 401
    {
        context.Response.ContentType = "application/json";


        await context.Response.WriteAsync(new { 
            Message = "You must be logged in to access this resource."
        }.ToString());
    }

    if (context.Response.StatusCode == (int)HttpStatusCode.Forbidden) // 403
    {
        context.Response.ContentType = "application/json";

        await context.Response.WriteAsync(new
        {
            Message = "Your claims are incorrect."
        }.ToString());
    }
});
kasprdev
  • 651
  • 1
  • 4
  • 14
  • thank you for your response. It gave the following output: can't parse JSON. Raw result: Skylink.DAL.Models.StandardModels.ErrorMessage – nour Dec 03 '21 at 09:58
  • how can I remove the "can't parse JSON" part? – nour Dec 03 '21 at 10:01