Aspire Support
.NET Aspire is an opinionated, cloud ready stack for building observable, production ready, distributed applications.
Keycloak.AuthServices.Aspire.Hosting adds a support to run Keycloak Instance as a component. It is intended to be used together with Keycloak.AuthServices.
See working example here. Examples/Aspire + Web API
Add to existing application
Install Keycloak.AuthServices.Aspire.Hosting package to "AppHost":
dotnet add package Keycloak.AuthServices.Aspire.HostingModify the AppHost/Program.cs:
// AppHost/Program.cs
var builder = DistributedApplication.CreateBuilder(args);
var keycloak = builder
.AddKeycloakContainer("keycloak");
var realm = keycloak.AddRealm("Test");
builder.AddProject<Projects.Api>("api").WithReference(keycloak).WithReference(realm);
builder.Build().Run();Here is what it does:
- Starts the instance of Keycloak as docker container.
WithReference(keycloak)adds Keycloak server instance to Service Discovery.WithReference(realm)addsKeycloak__RealmandKeycloak__AuthServerUrlenvironment variables.
From this point you are almost finished, the only this is left is to configure Authentication missing parts:
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var configuration = builder.Configuration;
builder.AddServiceDefaults();
services.AddKeycloakWebApiAuthentication(
configuration,
options =>
{
options.Audience = "workspaces-client";
options.RequireHttpsMetadata = false;
}
);
services.AddAuthorization();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/hello", () => "Hello World!").RequireAuthorization();
app.Run();Run:
dotnet run --project ./AppHostImport configuration files
You can reference import files and bind Keycloak data volumes to persist Keycloak configuration and share it with others.
var builder = DistributedApplication.CreateBuilder(args);
var keycloak = builder
.AddKeycloakContainer("keycloak")
.WithDataVolume()
.WithImport("./KeycloakConfiguration/Test-realm.json")
.WithImport("./KeycloakConfiguration/Test-users-0.json");
var realm = keycloak.AddRealm("Test");
builder.AddProject<Projects.Api>("api").WithReference(keycloak).WithReference(realm);
builder.Build().Run();TIP
You can sync your current configuration via CLI
Inside docker container run:
/opt/keycloak/bin/kc.sh export --dir /opt/keycloak/data/import --realm TestUse an external database
By default the Keycloak container uses the embedded H2 database, which is not suitable for anything beyond local exploration. Wire an external database via one of the typed extensions:
var postgres = builder
.AddPostgres("postgres")
.WithDataVolume()
.AddDatabase("keycloak-db", databaseName: "keycloak");
var keycloak = builder
.AddKeycloakContainer("keycloak")
.WithPostgresDatabase(postgres);The extension reads the resolved Aspire connection string at deploy time, translates it to JDBC, and sets KC_DB, KC_DB_URL, KC_DB_USERNAME, and KC_DB_PASSWORD on the Keycloak container. It also applies WaitFor(database), so Keycloak only starts after the database is ready.
Available overloads — one per Keycloak-supported vendor:
| Extension | KC_DB |
|---|---|
WithPostgresDatabase | postgres |
WithMySqlDatabase | mysql |
WithMariaDbDatabase | mariadb |
WithMsSqlDatabase | mssql |
WithOracleDatabase | oracle |
Each takes any IResourceBuilder<IResourceWithConnectionString>, so you can also point Keycloak at a managed database resource (e.g. an Aspire connection-string-only reference for a hosted Postgres).
Pin the issuer hostname
Keycloak in development mode derives the iss claim from whichever URL it is reached on. When API consumers run inside containers (e.g. host.docker.internal) but tokens were obtained via localhost, you'll see:
WWW-Authenticate: Bearer error="invalid_token", error_description="The issuer 'http://localhost:8080/realms/...' is invalid"Pin the hostname so every issued token uses the same iss regardless of how the container is reached:
var keycloak = builder
.AddKeycloakContainer("keycloak")
.WithHostname("http://localhost:8080/");This sets KC_HOSTNAME on the container. For non-Aspire scenarios see the containerized API recipe.
Start from Template
You can use Keycloak.AuthServices.Templates to scaffold the new Aspire Project that has Keycloak.AuthServices integration configured.
Install template:
dotnet new install Keycloak.AuthServices.TemplatesScaffold a solution:
dotnet new keycloak-aspire-starter -o $dev/KeycloakAspireStarter --EnableKeycloakImportSee Aspire Template for more details.