web-applicationsasp.net-core-webapi

.NET 8, Identity, Bearer issue


I'm building a web app (an authoritative server that will be used for a game I'm building) using ASP.NET Core 8, and I'm utilising Microsoft's Identity to do all authorisation and authentication.

Using Postman for testing Identity's AddIdentityApiEndpoints endpoints I'm able to successfully login a registered user, which returns:

{
    "tokenType": "Bearer",
    "accessToken": "CfDJ8...",
    "expiresIn": 3600,
    "refreshToken": "CfDJ8..."
}

Using the accessToken (I'm assuming this is what's required for the Bearer token's value within Postman), I attempt to hit an endpoint that right now does nothing but the controller's behind an [Authorize] tag. However I'm always getting 401 unauthorized.

Program.cs:

public class Program
{
     public static void Main(string[] args)
     {
         //CREATE WEBAPP BUILDER
         var builder = WebApplication.CreateBuilder(args);

         builder.Services.AddIdentityApiEndpoints<IdentityUser>(options =>
         {
             options.Password.RequiredLength = 6;
             options.Password.RequireNonAlphanumeric = false;
             options.Password.RequireDigit = false;
             options.Password.RequireUppercase = false;
             options.Password.RequireLowercase = false;
         })
            // .AddRoles<IdentityRole>()
             .AddEntityFrameworkStores<MM_DbContext>();

         builder.Services.AddAuthentication(options =>
         {
             options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
             options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
             //options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
         }).AddJwtBearer(options =>
         {
             options.TokenValidationParameters = new TokenValidationParameters
             {
                 ValidateIssuer = true,
                 ValidateAudience = false,
                 ValidateLifetime = true,
                 ValidateIssuerSigningKey = true,
                 ValidIssuer = builder.Configuration["JwtSettings:Issuer"],
                 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSettings:Key"]!))
             };
         });

         // ADD SERVICES - DI ALLOWS TEST / NONTEST SERVICES
         builder.Services

             .AddScoped<Services.IArmouryService, Services.TestArmouryService>()
             //.AddScoped<Services.IAuthenticationService, Services.TestAuthenticationService>()
             .AddScoped<Services.IBattleboardService, Services.TestBattleboardService>()
             .AddScoped<Services.ICharacterService, Services.TestCharacterService>()
             .AddScoped<Services.IKingdomService, Services.TestKingdomService>()
             .AddScoped<Services.ISoupkitchenService, Services.TestSoupkitchenService>()
             .AddScoped<Services.ITreasuryService, Services.TestTreasuryService>();

         // POSTGRESQL CONNECTION
         builder.Services.AddDbContext<MM_DbContext>(options =>
             options.UseNpgsql(builder.Configuration.GetConnectionString("Db")));
         System.Diagnostics.Debug.WriteLine($"Connection String: {builder.Configuration.GetConnectionString("Db")}");

         // ADD CONTROLLERS
         builder.Services.AddControllers().AddNewtonsoftJson(o => { });

         // ADD SWASHBUCKLE/SWAGGER
         builder.Services.AddEndpointsApiExplorer();
         builder.Services.AddSwaggerGen();

         // NEW WEBAPP
         var app = builder.Build();

         app.MapIdentityApi<IdentityUser>();

         // USE SWAGGER IF DEVELOPING
         if (app.Environment.IsDevelopment())
         {
             app.UseSwagger();
             app.UseSwaggerUI();
         }

         // MISC
         app.UseAuthentication();
         app.UseAuthorization();
         app.MapControllers();

         // RUN
         app.Run();
     }
}

KingdomController:

[Authorize]
[HttpPost("newmap")]
public async Task<ActionResult<IMapNewResponse>> NewMap([FromBody] MapNewPayload payload)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    try
    {
        var result = await _kingdomService.NewMap(payload);

        if (result is IMapNewResponse)
        {
            return Ok(result);
        }
        else
        {
            return StatusCode(500, "Unexpected error occurred"); //incorrect error code - unsure how to handle 
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine($"New map failed: {ex.Message}");
        return StatusCode(500, "Internal server error");
    }
}

I'm quite new to web servers and identity framework, as you can see in the code blocks I've submitted, I've already implemented a rudimentary Authentication system, but the time it would've taken me to iron out all of the features that Identity already provides out of the box just didn't seem worth it, I wanted to continue with developing the game, not an authentication/authorisation system.

I'm unsure what else to try or how to proceed.


Solution

  • I've got it working as following

    Basically the token generated is for Identity.Bearer

    builder.Services.AddAuthentication(options => {
        options.DefaultAuthenticateScheme = IdentityConstants.BearerScheme;
        options.DefaultChallengeScheme = IdentityConstants.BearerScheme;
        options.DefaultScheme = IdentityConstants.BearerScheme;
    }).AddBearerToken(IdentityConstants.BearerScheme);
    

    Debug