.NET Core Web API, JWT and Swagger - 401 is showing as Undocumented instead of Unauthorized

Viewed 11633

I have an ASP.NET Core Web API 3 app that implements a REST API and uses a JWT bearer token for authorization, and Swagger (Swashbuckle).

My controller has the [Authorize] filter on it, like:

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MyController : ControllerBase
{
}

Swagger works with my API, and I can generate a JWT token and give to Swagger and it all works well.

But if I try to use Swagger to hit one of my REST endpoints without a JWT token or invalid JWT token, the Swagger UI is showing an error 401 Undocumented, but all the examples I see out on the web show that I should be getting 401 Unauthorized.

(When I hit the same URL with Postman, it does show 401 Unauthorized.)

Before I start ripping out things, any ideas why I might be getting Undocumented instead of Unauthorized?

This is what I see:

enter image description here

When I add the attribute suggested below

 (ProducesResponseType(typeof(ProblemDetails), (int)HttpStatusCode.Unauthorized)])

I see this:

enter image description here

4 Answers

You can add app.UseStatusCodePages() in the Startup.cs.

This will then return a response body response body

Could you please try with below attribute in the action method,

 [ProducesResponseType(typeof(ProblemDetails), (int)HttpStatusCode.Unauthorized)] 

Maybe it is late, but I was into this problem so now I'll answer that.

It shows Undocumented because there is no bearer keyword existing at the beginning of your Authorization header. Probably your header is something like this:

Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNb3N0YWZhOTEiLCJqdGkiOiIzNGEzNjQwNC1iZWNjLTRhMmMtOGJkZi01ZDc1ZTBiY2QwZGIiLCJJZCI6IjEiLCJleHAiOjE2MTAyNDcyMTUsImlzcyI6Im1vaGFtYWRyYXZhZWkuaW5mbyIsImF1ZCI6Im1vaGFtYWRyYXZhZWkuaW5mbyJ9.0_kKI7F12o62A_QUZ38U9KVbBpnQMyO7kGcqBZzU4AU

so you should change it to:

Authorization: 
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJNb3N0YWZhOTEiLCJqdGkiOiIzNGEzNjQwNC1iZWNjLTRhMmMtOGJkZi01ZDc1ZTBiY2QwZGIiLCJJZCI6IjEiLCJleHAiOjE2MTAyNDcyMTUsImlzcyI6Im1vaGFtYWRyYXZhZWkuaW5mbyIsImF1ZCI6Im1vaGFtYWRyYXZhZWkuaW5mbyJ9.0_kKI7F12o62A_QUZ38U9KVbBpnQMyO7kGcqBZzU4AU

Actually Postman set the bearer at the beginning of Token and if you set Bearer but the Token is deprecated then the status code is going to show Unauthorized code.

any ideas why I might be getting Undocumented instead of Unauthorized?

Well because it's not documented by Swashbuckle.

One basically has two options:

Option one: Use XML-Comments on every [Authorize] endpoint, here is an example:

/// <summary>
/// StackOverflow example
/// </summary>
/// <response code="200">All good here</response>
/// <response code="401">Unauthorized</response>
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class MyController : ControllerBase
{

}

And implement Include descriptions from XML comments like this.

Option two: Use an operation filter once to add it to all [Authorized] endpoints:

Create a new class:

// using Microsoft.AspNetCore.Authorization;
// using Microsoft.OpenApi.Models;
// using Swashbuckle.AspNetCore.SwaggerGen;
public class AuthResponsesOperationFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        if (context != default && context.MethodInfo != default && context.MethodInfo.DeclaringType != default)
        {
            IEnumerable<AuthorizeAttribute> authAttributes = context.MethodInfo.DeclaringType.GetCustomAttributes(true)
                .Union(context.MethodInfo.GetCustomAttributes(true))
                .OfType<AuthorizeAttribute>();

            if (authAttributes.Any() && !operation.Responses.Any(r => r.Key == "401"))
                operation.Responses.Add("401", new OpenApiResponse { Description = "User not authenticated." });

            // if (authAttributes.Any() && !operation.Responses.Any(r => r.Key == "403"))
            //     operation.Responses.Add("403", new OpenApiResponse { Description = "User not authorized to access this endpoint." });
        }
    }
}

and set it in your Program.cs file (ASP.NET 6+):

builder.Services.AddSwaggerGen(c =>
{
    c.OperationFilter<AuthResponsesOperationFilter>();
};

or Startup.cs file (ASP.NET 5):

services.AddSwaggerGen(c =>
{
    c.OperationFilter<AuthResponsesOperationFilter>();
};

See here for more details: Swashbuckle Operation filters

Related