Skip to content

Replace ASP.NET Core Identity with Keycloak JWT ****** integration)#151

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/replace-aspnet-core-identity
Draft

Replace ASP.NET Core Identity with Keycloak JWT ****** integration)#151
Copilot wants to merge 4 commits intomainfrom
copilot/replace-aspnet-core-identity

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 17, 2026

The API previously owned both the identity store and auth endpoints via IdentityDbContext + MapIdentityApi<User>(). This replaces that with Keycloak as the OIDC provider; the API becomes a stateless JWT ****** server.

AppHost

  • Adds Aspire.Hosting.Keycloak and registers Keycloak on stable port 8080 (prevents browser cookie/session issues on restart) with OTLP export and realm import
  • API now references and waits for Keycloak before starting

Keycloak realm (Realms/finance-observer-realm.json)

  • finance-observer realm: email verification, registration, password reset enabled
  • Confidential client finance-observer-swagger with authorization code + PKCE for Scalar/OpenAPI UI
  • Bearer-only client finance-observer-api as the resource server audience
  • SMTP wired to MailDev (host maildev) for local transactional email
  • Password policy: min 8 chars, upper/lower/digit/special required

API (Startup/Program.cs)

Removes IdentityOptions config, MapIdentityApi<User>(), and AddIdentityEmailSending(); adds:

builder.Services.AddAuthentication()
    .AddKeycloakJwtBearer("keycloak", "finance-observer", options =>
    {
        options.Audience = "finance-observer-api";
        if (builder.Environment.IsDevelopment())
            options.RequireHttpsMetadata = false;
    });

UseAuthentication() is inserted before UseAuthorization(). OpenAPI document now includes an OIDC security scheme pointing to Keycloak's discovery endpoint on localhost:8080 (browser-accessible, not service-discovery).

User model & EF Core

  • User drops IdentityUser<Guid> base class; gains explicit Id, required string ExternalId (Keycloak sub), and string? Email
  • FinanceObserverContext changes base from IdentityDbContext<…> to DbContext
  • UserConfiguration adds ToTable("Users") and a unique index on ExternalId
  • New migration ReplaceIdentityWithKeycloak drops all seven AspNet* Identity tables, creates the new Users table, and re-targets foreign keys from Transaction and EmailUser

Removed

  • Microsoft.AspNetCore.Identity.EntityFrameworkCore and Microsoft.Extensions.Identity.Stores packages
  • AddIdentityApiEndpoints<User>().AddEntityFrameworkStores<>() DI registration
  • Identity.EmailSending project reference from Startup.csproj (Keycloak handles transactional auth emails natively)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • crl.comodoca.com
    • Triggering command: /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/9142823CD1647D8918F254C0BD1A1471/missingpackages_workingdir --packages /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/nugetconfig/nuget.config --force 2304�� DataAccess/DbAccess.EntityFrameworkCore/DbAccess.EntityFrameworkCore.csproj s2820864534 es /run/containerd/rm io.containerd.ru-f (dns block)
  • ocsp.comodoca.com
    • Triggering command: /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/.dotnet/dotnet /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/.dotnet/dotnet restore --no-dependencies /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/9142823CD1647D8918F254C0BD1A1471/missingpackages_workingdir --packages /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-3140803c200ce6d4/dbs/csharp/working/nugetconfig/nuget.config --force 2304�� DataAccess/DbAccess.EntityFrameworkCore/DbAccess.EntityFrameworkCore.csproj s2820864534 es /run/containerd/rm io.containerd.ru-f (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Replace ASP.NET Core Identity with Keycloak (OpenID Connect) using Aspire best practices</issue_title>
<issue_description>## Summary

Replace the current ASP.NET Core Identity + EF Core authentication stack with Keycloak as the centralised Identity and Access Management provider. The API will act as a stateless JWT Bearer resource server, validating tokens issued by Keycloak via OpenID Connect (OIDC). Aspire's first-party Keycloak integration is available and must be used throughout.

A placeholder project Server/DataAccess/IdentityAccess.Keycloak already exists in the solution, confirming this migration was planned.


Motivation

The current setup uses MapIdentityApi<User>() and IdentityDbContext, which means the API owns both the identity store and the auth endpoints. This couples application concerns with security concerns and does not scale well. Keycloak provides a production-ready, standards-compliant OIDC provider that handles login, registration, email verification, password reset, MFA, and token issuance — leaving the API free to focus on business logic.


Current State

Concern Current approach
User model User : IdentityUser<Guid> in Server/CrossCutting/Model/User.cs
DB context FinanceObserverContext : IdentityDbContext<User, IdentityRole<Guid>, Guid>
Identity registration AddIdentityApiEndpoints<User>().AddEntityFrameworkStores<FinanceObserverContext>() in DbAccess.EntityFrameworkCore/Extensions/HostApplicationBuilderExtensions.cs
Auth endpoints app.MapIdentityApi<User>() in Server/Presentation/Startup/Program.cs
Email verification Custom IdentityEmailSender : IEmailSender in Server/Logic/Business/Identity.EmailSending
Packages Microsoft.AspNetCore.Identity.EntityFrameworkCore, Microsoft.Extensions.Identity.Stores
AppHost No Keycloak resource

Target State

The API becomes a pure resource server. All authentication flows (register, login, token refresh, email verification, password reset) are delegated to Keycloak. The API only validates Bearer JWTs from Keycloak and applies authorization policies based on claims.


Tasks

1. AppHost – Add Keycloak resource (AspireInfrastructure/AppHost/Program.cs)

  • Add Aspire.Hosting.Keycloak NuGet package (current available version: 13.1.2-preview.1.26125.13) to AspireInfrastructure/AppHost/AppHost.csproj and Directory.Packages.props.
  • Register a Keycloak resource with a stable port (e.g. 8080) to avoid issues with browser cookies persisting OIDC sessions across AppHost restarts (Aspire Keycloak docs best practice):
    var keycloak = builder.AddKeycloak("keycloak", port: 8080)
        .WithOtlpExporter()            // export traces/metrics to Aspire dashboard
        .WithRealmImport("./Realms");  // import realm config on first start
  • Wire the API to reference and wait for Keycloak:
    IResourceBuilder<ProjectResource> api = builder.AddProject<Projects.Startup>("startup")
        // ... existing env vars ...
        .WithReference(keycloak)
        .WaitFor(keycloak)
        // ... existing references ...
  • Note: Do not use WithDataVolume() for the Keycloak resource during early development to avoid state management issues when restarting the app (Aspire best practice).
  • Update Directory.Packages.props to add the new package version entry.

2. Keycloak realm configuration

  • Create a Realms/ directory in the AppHost project containing a realm import JSON file.
  • The realm configuration must include:
    • A dedicated realm (e.g. finance-observer)
    • A confidential client for the Scalar/OpenAPI UI (authorization code flow + PKCE, e.g. finance-observer-swagger)
    • Email settings pointing to the MailDev SMTP server for local development
    • Email verification enabled (Keycloak replaces the current IdentityEmailSender)
    • Password policy matching the current requirements (min 8 characters, 4 unique characters)
    • Appropriate roles/scopes mirroring any existing authorization requirements

3. API – Replace Identity auth with JWT Bearer (Server/Presentation/Startup/Program.cs)

  • Add Aspire.Keycloak.Authentication NuGet package to Server/Presentation/Startup/Startup.csproj and Directory.Packages.props.
  • Remove:
    • builder.Services.Configure<IdentityOptions>(...)
    • builder.Services.AddAuthorization() replacement is fine to keep but clean up
    • app.MapIdentityApi<User>()
  • Add JWT Bearer authentication using the Aspire Keycloak client integration:
    builder.Services.AddAuthentication()
        .AddKeycloakJwtBearer(
            serviceName: "keycloak",
            realm: "finance-observer",
            options =>
            {
                options.Audience = "finance-observer-api";
                // OIDC best practice: only di...

📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

FlorianAlbert and others added 3 commits March 17, 2026 19:46
… integration

Co-authored-by: FlorianAlbert <61190722+FlorianAlbert@users.noreply.github.com>
…tity' into copilot/replace-aspnet-core-identity
Copilot AI changed the title [WIP] Replace ASP.NET Core Identity with Keycloak integration Replace ASP.NET Core Identity with Keycloak JWT ****** integration) Mar 17, 2026
Copilot AI requested a review from FlorianAlbert March 17, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace ASP.NET Core Identity with Keycloak (OpenID Connect) using Aspire best practices

2 participants