using System.Security.Claims; using Distribution.Data; using Distribution.Features.Auth; using Distribution.Features.Brand; using Distribution.Features.Category; using Distribution.Features.DeliveryRide; using Distribution.Features.Payment; using Distribution.Features.DriverComplianceConfig; using Distribution.Features.DriverProfile; using Distribution.Features.Grn; using Distribution.Features.Item; using Distribution.Features.Order; using Distribution.Features.PriceList; using Distribution.Features.Po; using Distribution.Features.PurchaseReturn; using Distribution.Features.Returns; using Distribution.Features.Claims; using Distribution.Features.SupplierClaims; using Distribution.Features.Region; using Distribution.Features.LoadingEvent; using Distribution.Features.Ride; using Distribution.Features.Role; using Distribution.Features.Route; using Distribution.Features.Sale; using Distribution.Features.Scheme; using Distribution.Features.Store; using Distribution.Features.Store.Kyc; using Distribution.Features.Supplier; using Distribution.Features.Sync; using Distribution.Features.Uom; using Distribution.Features.User; using Distribution.Features.Vehicle; using Distribution.Features.Stock; using Distribution.Features.Warehouse; using Distribution.Infra.Authorization; using Distribution.Infra.UoW; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; var builder = WebApplication.CreateBuilder(args); var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' was not found."); builder.Services.AddDbContext(options => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped(); builder.Services.AddHttpClient(client => { var baseUrl = builder.Configuration["AuthHex:BaseUrl"] ?? throw new InvalidOperationException("AuthHex:BaseUrl is not configured."); client.BaseAddress = new Uri(baseUrl); }); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddSingleton(); var jwtSection = builder.Configuration.GetSection("Jwt"); var jwtPublicKeyXml = jwtSection["PublicKey"] ?? throw new InvalidOperationException("Jwt:PublicKey is not configured."); var jwtSigningKey = new RsaSecurityKey(RsaXmlKeyReader.ReadPublicKey(jwtPublicKeyXml)); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = jwtSection["Issuer"], ValidateAudience = true, ValidAudience = jwtSection["Audience"], ValidateIssuerSigningKey = true, IssuerSigningKey = jwtSigningKey, ValidateLifetime = true, ClockSkew = TimeSpan.FromMinutes(1) }; // AuthHex issues the token and owns its claim shape; this app's authorization (permission // policies, role-level checks) runs against the *local* Role/Permission tables, so every // validated token is mapped back to a local User/Role once here, not duplicated per // endpoint. A token for a user with no matching local User record is rejected outright — // login via AuthHex does not implicitly provision a local user. options.Events = new JwtBearerEvents { OnTokenValidated = async context => { var subClaim = context.Principal?.FindFirst("sub")?.Value ?? context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (!Guid.TryParse(subClaim, out var userId)) { context.Fail("Token is missing a valid user id claim."); return; } var userRepo = context.HttpContext.RequestServices.GetRequiredService(); var user = await userRepo.GetByIdAsync(userId); if (user is null || !user.IsActive) { context.Fail("User not found or inactive."); return; } var identity = (ClaimsIdentity)context.Principal!.Identity!; identity.AddClaim(new Claim("username", user.Username)); identity.AddClaim(new Claim("role_id", user.FK_RoleId.ToString())); identity.AddClaim(new Claim("role_level", (user.Role?.Level ?? 0).ToString())); } }; }); builder.Services.AddAuthorization(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddOpenApi(); builder.Services.AddSwaggerGen(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.MapOpenApi(); app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();