using System.Security.Cryptography; using System.Text; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using OpenWarehouse.auth.api.Common.AuthTokenRepo; namespace OpenWarehouse.auth.api.Services; public static class AuthenticationConfigService { public static T AddAuthenticationService(this T builder) where T : IHostApplicationBuilder { var privateKeyPath = Path.Combine(builder.Environment.ContentRootPath, "private_key_pkcs8.pem"); var rsa = RSA.Create(); if (!File.Exists(privateKeyPath)) { rsa = RSA.Create(2048); var privateKeyPem = ExportPrivateKeyToPem(rsa); File.WriteAllText(privateKeyPath, privateKeyPem); Console.WriteLine($"Generated new RSA private key at: {privateKeyPath}"); } else { var privateKey = File.ReadAllText(privateKeyPath); rsa.ImportFromPem(privateKey); } var rsaPublic = rsa.ExportParameters(false); var rsaSecurityKey = new RsaSecurityKey(rsa) { KeyId = "1" }; // Configure JWT Bearer authentication builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = rsaSecurityKey, ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes( builder.Configuration["Jwt:AesKey"] ?? throw new InvalidOperationException("Missing Jwt:AesKey in configuration"))), ValidAudience = builder.Configuration["Jwt:Audience"], ValidIssuer = builder.Configuration["Jwt:Issuer"], }; options.Events = new JwtBearerEvents { OnTokenValidated = async context => { var tokenBlacklistService = context.HttpContext.RequestServices.GetRequiredService(); var token = context.SecurityToken.Id; if (await tokenBlacklistService.TokenIsLock(guid: token)) { context.Fail("This token has been revoked."); } }, }; }); builder.Services.AddSingleton(new { keys = new[] { new { kty = "RSA", e = Base64UrlEncoder.Encode(rsaPublic.Exponent), n = Base64UrlEncoder.Encode(rsaPublic.Modulus), use = "sig", alg = "RS256" } } }); return builder; } private static string ExportPrivateKeyToPem(RSA rsa) { var privateKeyBytes = rsa.ExportPkcs8PrivateKey(); var builder = new StringBuilder(); builder.AppendLine("-----BEGIN PRIVATE KEY-----"); builder.AppendLine(Convert.ToBase64String(privateKeyBytes, Base64FormattingOptions.InsertLineBreaks)); builder.AppendLine("-----END PRIVATE KEY-----"); return builder.ToString(); } }