I have a simple minimal API configured with the help of the Carter library as following:

public void AddRoutes(IEndpointRouteBuilder app)
{  
     // Group for /api/user endpoints
     var group = app.MapGroup("/api/user/");

     // Methods for  /api/user/id endpoints
     group.MapGet("{id}", GetUserById).WithName(nameof(GetUserById)).
         Produces(StatusCodes.Status200OK).
         Produces(StatusCodes.Status400BadRequest).
         Produces(StatusCodes.Status401Unauthorized).RequireAuthorization();
 }

With the GetUserById method like this:

[Authorize(AuthenticationSchemes = Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)]
public static async Task<Results<Ok<UserDataDTO>, BadRequest<string>>> GetUserById(int id, IUserLogic userLogic)
{
    var user = await userLogic.GetUserByIdAsync(id);

    if (user is null)
        return TypedResults.BadRequest("User with the specified doesn't exist.");

    var userData = new UserDataDTO(user);

    return TypedResults.Ok(userData);
}

When I try to run the endpoint via Swagger, I simply cannot executed this as intended; I get an 401 Unauthorized response. When configuring this through code, I simply cannot get it to work, even though I tried a few things including this snippet of code which generates everything I need:

 builder.Services
     .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
     .AddJwtBearer(o => o.TokenValidationParameters = new()
     {
         ValidateIssuer = true,
         ValidateAudience = true,
         ValidateLifetime = true,
         ValidateIssuerSigningKey = true,
         // Read from appsettings.json ...WARNING VALUES MUST BE THE SAME IN ALL IMPLEMENTATIONS.

         // BETTER, CLEANER WAY?
         IssuerSigningKey = new SymmetricSecurityKey(
             Encoding.UTF8.GetBytes(builder.Configuration
             .GetSection("JwtSecurityTokenConfiguration").
             Get<JwtSecurityTokenConfiguration>().SecretKey)),
         ValidIssuer = builder.Configuration
             .GetSection("JwtSecurityTokenConfiguration").
             Get<JwtSecurityTokenConfiguration>().Issuer,
         ValidAudience = builder.Configuration
             .GetSection("JwtSecurityTokenConfiguration").
             Get<JwtSecurityTokenConfiguration>().Audience
     });

 // Carter
 builder.Services.AddHttpContextAccessor();
 builder.Services.AddCarter();

 // Add services to the container.
 builder.Services.AddAuthorization();

 // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
 builder.Services.AddEndpointsApiExplorer();
 builder.Services.AddSwaggerGen(swagger =>
 {
     swagger.SwaggerDoc("v1", new OpenApiInfo()
     {
         Description = "User microservice for E-commerce app.",
         Title = "RSO project.",
         Version = "v1",
         Contact = new OpenApiContact()
         {
             Name = "Aleksander Kovac & Urban Poljsak",
             Url = new Uri("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
         }
     });
     swagger.AddSecurityDefinition("jwt_auth", new OpenApiSecurityScheme()
     {
         Description = "Basic authorization with JWT token.",
         Name = "Bearer",
         BearerFormat = "JWT",
         In = ParameterLocation.Header,
         Type = SecuritySchemeType.ApiKey
     });
     swagger.AddSecurityRequirement(new OpenApiSecurityRequirement()
     {
         {new OpenApiSecurityScheme()
         {
             Reference = new OpenApiReference()
             {
                 Id="jwt_auth",
                 Type = ReferenceType.SecurityScheme
             }
         },Array.Empty<string>() },
     });
 });

 // APP.
 var app = builder.Build();

 // Carter
 app.MapCarter();

 app.UseSwagger();
 app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "API"));

 app.UseAuthentication();
 app.UseAuthorization();

I am generating my token as follows:

public string GetJwtToken(User existingUser)
{
    var claims = new Claim[] {
        new(JwtRegisteredClaimNames.Sub,existingUser.UserId.ToString()),
        new(JwtRegisteredClaimNames.Email,existingUser.UserEmail),
        new(JwtRegisteredClaimNames.AuthTime, DateTime.UtcNow.ToString()),
    };

    var signingCredentials = new SigningCredentials(
        new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtConfiguration.SecretKey)),
        SecurityAlgorithms.HmacSha256);

    var jwtToken = new JwtSecurityToken(
        _jwtConfiguration.Issuer,
        _jwtConfiguration.Audience,
        claims,
        DateTime.UtcNow.AddSeconds(-5),
        DateTime.UtcNow.AddDays(7),
        signingCredentials);

    return new JwtSecurityTokenHandler().WriteToken(jwtToken);
}

So how to

  1. Solve this issue of receiving the 401 Unauthorized error in my application?
  2. Use the JWT in my API endpoint to use the data?
  3. Remove the lock icon from /login and /register endpoints?
  4. Properly read the JWT data from the appsetting.{Environment}.json file?
  5. Insert the JWT into the Swagger authorize field.
1

There are 1 best solutions below

0
On

Well based on your scenario and description it seems your question is too big to fit in within the one answer, it would be great if you would have been asked very specific question within one post. However, I am trying to explain you shorter steps how you can proceed further.

If you encounter any issue base on that particular problem you may post new question that would be easier to provide correct answer.

Let's take a look at your questions.

How to solve this issue of receiving the 401 Unauthorized error in my application?

As said earlier the very common reason for 401 is when the credential doesn't match with the token passed.

In order to check that, you can check your token in any token decoder. You can check here jwt.io

In addition, please check your ValidIssuer and ValidAudience parameters in your JWT configuration. Apart from that, Inspect the headers and payload of the JWT token to ensure that it contains the necessary information.

Make sure, your middleware order is correct like following:

app.UseAuthentication();
app.UseAuthorization();

How to Use the JWT in my API endpoint to use the data?

In order to obtained user's data in your API endpoints from your token you can do as following:

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[HttpGet("/api/user/profile")]
public IActionResult GetUserProfile()
{
   
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    var userEmail = User.FindFirst(ClaimTypes.Email)?.Value;
    return Ok(userData);
}

How to Remove the lock icon from /login and /register endpoints

Well, if you want to remove the lock icon from specific endpoints you can achieve this by allowing anonymous access to these endpoints.

In ASP.NET Core, you can use the [AllowAnonymous] attribute to specify that a particular controller or action should not require authentication. You can do like below:

[AllowAnonymous]
[HttpPost("register")]
public IActionResult Register([FromBody] RegisterModel model)
{
    return Ok(new { Message = "User registered successfully." });
}

How to Properly read the JWT data from the appsetting.{Environment}.json file

This can be read in many ways, you may have class or you can directly read the json file in program.cs file. You can take a look be exmaple:

Let say, you have following property:

{
  "JwtSettings": {
    "Issuer": "your-dev-issuer",
    "Audience": "your-dev-audience",
    "Key": "your-dev-secret-key"
  }
}

So you can do like below:

var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var IssuerValue = configuration.GetValue<string>("JwtSettings:Issuer");

You also can read using builder service middleware by do as below:

builder.Services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings"));

How to insert the JWT into the Swagger authorize field.

To to that, you can use the Swagger UI configuration in your application. Write below snippet within your program.cs file:

builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Your API", Version = "v1" });
    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    c.IncludeXmlComments(xmlPath);
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.ApiKey,
        Scheme = "Bearer"
    });

    c.AddSecurityRequirement(new OpenApiSecurityRequirement
        {
            {
                new OpenApiSecurityScheme
                {
                    Reference = new OpenApiReference
                    {
                        Type = ReferenceType.SecurityScheme,
                        Id = "Bearer"
                    }
                },
                new List<string>()
            }
        });
});

After that, resgiter that in middleware:

    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "Your API V1");
        c.ConfigureOAuth2("Bearer", "", "", "Swagger", "", "");
    });

Note: Above explnation is not exact solution for your scenario. I am trying to assist you, regarding how you can proceed furhter. If you encounter any issue, please ask the very specific issue within one question so that it would be quite easier to help you quickly. In addition, please refer to this official document as well.