# Task 3: Configure OpenIddict ## Task Description **Files:** - Create: `src/Fengling.AuthService/Configuration/OpenIddictSetup.cs` - Modify: `src/Fengling.AuthService/Program.cs` ## Implementation Steps ### Step 1: Create OpenIddict configuration Create: `src/Fengling.AuthService/Configuration/OpenIddictSetup.cs` ```csharp using Microsoft.Extensions.DependencyInjection; using OpenIddict.Validation.AspNetCore; namespace Fengling.AuthService.Configuration; public static class OpenIddictSetup { public static IServiceCollection AddOpenIddictConfiguration(this IServiceCollection services, IConfiguration configuration) { services.AddOpenIddict() .AddCore(options => { options.UseEntityFrameworkCore() .UseDbContext(); }) .AddServer(options => { options.SetIssuer(configuration["OpenIddict:Issuer"] ?? "https://auth.fengling.local"); options.AddSigningKey(new SymmetricSecurityKey( System.Text.Encoding.UTF8.GetBytes("fengling-super-secret-key-for-dev-only-change-in-prod-please!!!"))); options.AllowAuthorizationCodeFlow() .AllowPasswordFlow() .AllowRefreshTokenFlow() .RequireProofKeyForCodeExchange(); options.RegisterScopes("api", "offline_access"); options.AddDevelopmentEncryptionCertificate() .AddDevelopmentSigningCertificate(); options.UseAspNetCore() .EnableAuthorizationEndpointPassThrough() .EnableTokenEndpointPassThrough() .EnableLogoutEndpointPassThrough(); }) .AddValidation(options => { options.UseLocalServer(); options.UseAspNetCore(); }); services.AddAuthentication(options => { options.DefaultAuthenticateScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme; }); return services; } } ``` ### Step 2: Update Program.cs with OpenIddict and EF Core Edit: `src/Fengling.AuthService/Program.cs` ```csharp using Fengling.AuthService.Configuration; using Fengling.AuthService.Data; using Fengling.AuthService.Models; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using OpenTelemetry; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using Serilog; var builder = WebApplication.CreateBuilder(args); // Serilog Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(builder.Configuration) .Enrich.FromLogContext() .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .CreateLogger(); builder.Host.UseSerilog(); // Database builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); // Identity builder.Services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); // OpenIddict builder.Services.AddOpenIddictConfiguration(builder.Configuration); // OpenTelemetry builder.Services.AddOpenTelemetry() .ConfigureResource(resource => resource.AddService("Fengling.AuthService")) .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddSource("OpenIddict.Server.AspNetCore") .AddOtlpExporter(); // Controllers builder.Services.AddControllers(); // Swagger builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Fengling Auth Service", Version = "v1", Description = "Authentication and authorization service using OpenIddict" }); options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme { Type = SecuritySchemeType.OAuth2, Flows = new OpenApiOAuthFlows { Password = new OpenApiOAuthFlow { TokenUrl = "/connect/token" } } }); }); var app = builder.Build(); // Configure pipeline app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Fengling Auth Service v1"); options.OAuthClientId("swagger-ui"); options.OAuthUsePkce(); }); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); ``` ### Step 3: Run to verify startup Run: ```bash dotnet run ``` Expected: Service starts without errors, Swagger UI available at http://localhost:5000/swagger ### Step 4: Commit ```bash git add src/Fengling.AuthService/Configuration/ src/Fengling.AuthService/Program.cs git commit -m "feat(auth): configure OpenIddict with JWT and OAuth2 support" ``` ## Context This task configures OpenIddict for OAuth2/OIDC authentication, including: - Server configuration with token endpoints - Password flow for user authentication - Development certificates for signing - Integration with ASP.NET Core Identity - Swagger UI with OAuth2 support **Tech Stack**: OpenIddict 7.2.0, ASP.NET Core Identity, Swagger ## Verification - [ ] OpenIddictSetup class created - [ ] Program.cs updated with OpenIddict configuration - [ ] Service starts without errors - [ ] Swagger UI accessible - [ ] Committed to git ## Notes - Using symmetric key for token signing (dev only) - Password flow enabled for direct authentication - Development certificates used (replace in production)