How to run Curity Identity Server container in .NET Aspire solution?
This post explains how to set up .NET Aspire solution which runs Curity Identity Server container and shows the power of .NET Aspire container orchestration.
Typically, a local development environment is configured to use Identity Server from the Cloud Dev or Test environment. Practically, this also means that you can't develop your solution offline.
This approach enables developers to play around and adjust Curity Identity Server configurations directly from the own machine.
What is Curity Identity Server?
The Curity Identity Server is an identity and access management solution designed to secure APIs, applications, and websites. Curity supports industry-standard protocols such as OAuth (authorization) and OpenID Connect (authentication) for identity and access management. EntraID, Keycloak, and Duende IdentityServer are comparable solutions to Curity.
I will use the free Community Edition of Curity Identity Server, as it includes all the essential features of the standard version.
Let's get started
1. Acquire a Community Edition License from Curity
Open this site, fill your email address and confirm, and then you're good to go.
The content of the license looks like this:
{
"Company":"e@mail.com",
"Issued":"2024-12-31",
"Expires":"2025-12-31",
"Tier":"Subscription",
"Product":"Identity Server",
"Version":"4.3",
"Feature":"",
"Edition":"Community",
"Groups":"1",
"Environment":"",
"Type":"Production",
"GracePeriod":"30",
"License":"[REMOVED]"
}
2. Install Docker Desktop or Podman.
.NET Aspire projects can run containers using Docker Desktop or Podman runtimes.
3. Running Curity Identity Server on Docker Desktop (optional)
Curity has good documentation about how to run Curity in Docker available here.
Pull the image
docker pull curity.azurecr.io/curity/idsvr
Run the container
docker run -it -e PASSWORD=<admin_user_password> -p 6749:6749 -p 8443:8443 curity.azurecr.io/curity/idsvr:9.7.0
Port 6749 serves as the default port for the admin user interface. Later, I will show how to format this configuration for the .NET Aspire solution.
4. Running Curity Identity Server container in .NET Aspire solution
- Copy Curity license file to a folder C:\Curity\Data\license.json
- Create a new empty .NET Aspire solution in Visual Studio.
- Add the following code block to the Program.cs of the AppHost project.
var curityAdminPassword = builder.AddParameter("curityAdminPassword", secret: true);
var adminUiPort = 6749;
var authorizationServerPort = 8443;
var curity = builder.AddContainer("curity", "curity.azurecr.io/curity/idsvr")
.WithEndpoint(adminUiPort, adminUiPort, name: "adminui", scheme: "https")
.WithEndpoint(authorizationServerPort, authorizationServerPort, name: "authorizationserver", scheme: "https")
.WithBindMount(@"C:\Curity\Data\license.json", "/opt/idsvr/etc/init/license/license.json").WithLifetime(ContainerLifetime.Persistent)
.WithEnvironment("PASSWORD", curityAdminPassword.Resource.Value);
Same configuration in docker-compose.yml:
version: '3.2'
services:
admin:
image: curity.azurecr.io/curity/idsvr
command: ["sh", "-c", "idsvr -s admin"]
environment:
- PASSWORD=<ADMIN_USER_PASSWORD>
ports:
- 6749:6749
volumes:
- ./license/license.json:/opt/idsvr/etc/init/license/license.json
runtime:
image: curity.azurecr.io/curity/idsvr
environment:
- SERVICE_ROLE=default
ports:
- 8443:8443
depends_on:
- admin
The above .NET Aspire setup fetches the Curity Identity Server image from Curity's ACR and enables HTTPS access to the Admin UI on port 6749. The authorization server processes requests using port 8443.
WithBindMount maps local license file from C:\Curity\Data\license.json to container's path /opt/idsvr/etc/init/license/license.json. When this configuration is in place, you don't need to configure license manually via Admin Ui during the first login.
Lastly, an environment variable called "PASSWORD" is set to determine the administrator's password for Admin UI. Actual password is retrieved from the appsettings.json file.
- Add this configuration to the appsettings.json file in the AppHost project
{
"Parameters": {
"curityAdminPassword": "[PASSWORD]"
}
}
Now the solution is ready for a first launch.
- Open this site https://localhost:6749/admin and login using username admin and password determined in the appsettings.json.
5. Curity configuration after logging in
After first login, you need to configure the Curity environment such as Authentication & Token Service, and necessary clients. The configuration wizard should not prompt for any license-related information, as the license file has already been set up through the container configuration in the .NET Aspire AppHost.
Refer to this link for configuration instructions: https://curity.io/resources/learn/first-config/.
6. Export Curity configuration
Once you have completed the configuration, download the Curity configuration using existing functionality. Follow this instruction https://curity.io/resources/learn/import-export-config/.
- Copy the XML-based Curity configuration file to C:\Curity\Data\curity-config.xml
7. Update the Curity configuration in the .NET Aspire AppHost
- Include WithBindMount (curity-config.xml) in the container setup.
var curity = builder.AddContainer("curity", "curity.azurecr.io/curity/idsvr")
.WithEndpoint(adminUiPort, adminUiPort, name: "adminui", scheme: "https")
.WithEndpoint(authorizationServerPort, authorizationServerPort, name: "authorizationserver", scheme: "https")
.WithBindMount(@"C:\Curity\Data\license.json", "/opt/idsvr/etc/init/license/license.json").WithLifetime(ContainerLifetime.Persistent)
.WithBindMount(@"C:\Curity\Data\curity-config.xml", "/opt/idsvr/etc/init/curity-config.xml").WithLifetime(ContainerLifetime.Persistent)
.WithEnvironment("PASSWORD", curityAdminPassword.Resource.Value);
This setup enables that pre-defined Curity configuration is used in every debugging session.
8. Create dependency between IDP and API in .NET Aspire AppHost
Use the WaitFor method to ensure that the Curity Identity Provider is fully operational. Besides that, configure also a WithReference method call with an explicit reference to an authorization server endpoint.
var api = builder.AddProject<Api>("api")
.WaitFor(curity)
.WithReference(curity.GetEndpoint("authorizationserver"));
This enables you to inject an authorization server URL to an API project. This environment variable can then easily be used to configure authentication/authorization at an API-level.

Summary
This demonstrates how easily you can orchestrate containers in .NET Aspire solution. The intuitive .NET Aspire application model simplifies this process. I prefer the .NET Aspire orchestration model over the Docker compose.
It's convenient to run IDP in your local development environment within the frontend and API applications. It's easy to change identity provider configuration and test different things locally. Also, this approach enables offline development experience.
This example shows how easy it is to run third party containers within the .NET Aspire solution.
Comments