I am running into an issue with trying to use .NET Identity with a MongoDB backend. The problem is related to authorization. I want the API to use JWT but it would seem the package I am using defaults to Cookies. The problem is that even when I try to turn off Cookies it fails. In other words I don't want the Mongo Identity handling incoming authorizations, I just want to take advantage of its backend user controls (failed logins, etc).
program.cs:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ClockSkew = TimeSpan.FromMinutes(5),
ValidIssuer = builder.Configuration["JwtSettings:Issuer"],
ValidAudience = builder.Configuration["JwtSettings:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JwtSettings:Key"])),
// This tells the framework how to interpret the role claim
RoleClaimType = ClaimTypes.Role // or "role"
};
// Add detailed logging for authentication events
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Debug.WriteLine($"Authentication failed: {context.Exception.Message}");
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
foreach (var claim in context.Principal.Claims)
{
Debug.WriteLine("Claim: {Type} = {Value}", claim.Type, claim.Value);
}
return Task.CompletedTask;
},
OnChallenge = context =>
{
Debug.WriteLine($"Authentication challenge: {context.Error}, {context.ErrorDescription}");
return Task.CompletedTask;
}
};
});
builder.Services.AddAuthorizationBuilder()
.AddPolicy("AdminPolicy", policy => policy.RequireRole("Admin"))
.AddPolicy("SuperAdminPolicy", policy => policy.RequireRole("SuperAdmin"))
.AddPolicy("UserPolicy", policy => policy.RequireRole("User"));
// Setting up to user MS Identity for users and roles. This is unique because it is using MongoDB vs SQL Server
var mongoDbSettings = builder.Configuration.GetSection(nameof(MongoDBSettings)).Get<MongoDBSettings>();
builder.Services.AddIdentityMongoDbProvider<ApplicationUser, MongoRole>(identity =>
{
identity.Password.RequiredLength = 8;
identity.Password.RequireDigit = true;
identity.Password.RequiredLength = 8;
identity.Password.RequireNonAlphanumeric = true;
identity.Password.RequireUppercase = true;
identity.Password.RequireLowercase = true;
// Lockout settings
identity.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
identity.Lockout.MaxFailedAccessAttempts = 20;
// ApplicationUser settings
identity.User.RequireUniqueEmail = false;
identity.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#!%&*()^.-_";
},
mongo =>
{
mongo.ConnectionString = mongoDbSettings?.IdentityConnectionString;
mongo.UsersCollection = "Identity";
mongo.RolesCollection = "Roles";
}).AddDefaultTokenProviders();
builder.Services.Configure<IdentityOptions>(options =>
{
options.SignIn.RequireConfirmedAccount = false;
});
builder.Services.ConfigureApplicationCookie(options =>
{
// Disable cookie authentication
options.Cookie.Name = "Disabled";
options.ExpireTimeSpan = TimeSpan.Zero;
options.SlidingExpiration = false;
// Prevent redirects for APIs
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
options.Events.OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
};
});
Is there a way to stop cookie auth and instead use the JWT Auth, in API controller calls like this one:
[Authorize(Roles = "Admin,SuperAdmin")]
[HttpGet]
[Route("accounts")]
public ActionResult<AccountResult> Accounts(bool activeOnly)
{
return _accountClient.GetAll(activeOnly);
}