When I learned to implement authorization in my WebAPI and tested it in Swagger, I noticed the “Available authorization” page was empty (after clicking the lock icon):

For those who don’t know Swagger, you can think of this as a framework that offers a systematic way of notating the interface of any RESTful service under the OpenAPI specification. Today I will not talk in-depth (but you can follow this link if you want to) about how to build API and use Swagger. But more into the problem that I got earlier.
The root cause of the problem (Available authorization empty) is that the authorization response can’t identify your setup (based on this thread in StackOverflow and a reply by ahmeticat).
You need to make sure you install the below NuGet packages:
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.2" />
For Authorization Logic, I create the below class (I’m using MediatR):
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using LearningCqrs.Core;
using LearningCqrs.Data;
using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
namespace LearningCqrs.Features.Users;
public class Authorize
{
public record AuthorizeCommand(string Username, string Password) : IRequest<string>;
public class AuthorizeHandler : IRequestHandler<AuthorizeCommand, string>
{
private readonly BlogContext _dbContext;
public AuthorizeHandler(BlogContext dbContext)
{
_dbContext = dbContext;
}
public async Task<string> Handle(AuthorizeCommand request, CancellationToken cancellationToken)
{
var user = await _dbContext.Users.SingleAsync(e => e.Username == request.Username, cancellationToken);
var passwordHasher = new PasswordHasher<User>();
var result = passwordHasher.VerifyHashedPassword(user, user.Password, request.Password);
if(result == PasswordVerificationResult.Failed) throw new InvalidOperationException("Username or Password is incorrect");
var claims = new[]
{
new Claim(ClaimTypes.Name, request.Username),
new Claim(ClaimTypes.Role, Settings.Role)
};
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetConnectionString("AppId")));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var tokenDescriptor = new JwtSecurityToken(issuer: Configuration.GetConnectionString("ValidIssuer"),
audience: Configuration.GetConnectionString("ValidAudience"), claims, expires: DateTime.Now.AddHours(2),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
}
}
}
Then you need to create AuthResponsesOperationFilter to Filter the correct Auth result in the UI:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace LearningCqrs.Core;
// https://stackoverflow.com/questions/49908577/empty-authorization-header-on-requests-for-swashbuckle-aspnetcore
public class AuthResponsesOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var authAttributes = context.MethodInfo.DeclaringType?.GetCustomAttributes(true)
.Union(context.MethodInfo.GetCustomAttributes(true))
.OfType<AuthorizeAttribute>();
if (authAttributes == null || !authAttributes.Any()) return;
var securityRequirement = new OpenApiSecurityRequirement()
{
{
// Put here you own security scheme, this one is an example
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = JwtBearerDefaults.AuthenticationScheme
},
Scheme =JwtBearerDefaults.AuthenticationScheme,
Name = HeaderNames.Authorization,
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
BearerFormat = "JWT"
},
new List<string>()
}
};
operation.Security = new List<OpenApiSecurityRequirement> { securityRequirement };
operation.Responses.Add("401", new OpenApiResponse { Description = "Unauthorized" });
}
}
Here is my AddSwaggerGen code:
serviceCollection.AddSwaggerGen(opt =>
{
var securityDefinition = new OpenApiSecurityScheme
{
Type = SecuritySchemeType.Http,
In = ParameterLocation.Header,
Name = HeaderNames.Authorization,
Scheme = JwtBearerDefaults.AuthenticationScheme
};
opt.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, securityDefinition);
opt.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{securityDefinition, Array.Empty<string>()}
});
opt.OperationFilter<AuthResponsesOperationFilter>();
});
Because you want to implement Authorization, you need to add AuthorizeAttribute in your Controller. Below is the sample of my UsersController:
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace LearningCqrs.Controllers;
[Authorize]
[Route("api/users")]
[ApiController]
public class UsersController : ControllerBase
{
private readonly IMediator _mediator;
public UsersController(IMediator mediator)
{
_mediator = mediator;
}
[AllowAnonymous]
[HttpPost("authenticate")]
public async Task<ActionResult> Authenticate([FromBody]Features.Users.Authorize.AuthorizeCommand authorizeCommand,
CancellationToken cancellationToken)
{
try
{
var result = await _mediator.Send(authorizeCommand, cancellationToken);
return Ok(result);
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
[HttpPost]
public async Task<ActionResult> AddProduct([FromBody] Features.Users.Create.CreateUserCommand createUserCommand,
CancellationToken cancellationToken)
{
var result = await _mediator.Send(createUserCommand, cancellationToken);
return Ok(result);
}
[HttpGet("getbyusername")]
public async Task<ActionResult> GetUserByUsername([FromQuery] Features.Users.GetByUsername.GetByUsernameQuery getByUsernameQuery,
CancellationToken cancellationToken)
{
var result = await _mediator.Send(getByUsernameQuery, cancellationToken);
return Ok(result);
}
}
And here is the result:

Happy coding!