Skip to content

Commit 88d5e7e

Browse files
committed
Added keycloak integration blog post
1 parent 9daf78b commit 88d5e7e

File tree

4 files changed

+250
-0
lines changed

4 files changed

+250
-0
lines changed
78.5 KB
Loading
85.9 KB
Loading
193 KB
Loading
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
2+
# Integrating Keycloak with ASP.NET Zero
3+
4+
Centralized authentication is a common requirement in enterprise applications.
5+
**Keycloak** provides a powerful open-source Identity and Access Management system, while
6+
**ASP.NET Zero** offers a ready-to-run application framework built on ASP.NET Core with multi-tenant, user management and many more [features](https://aspnetzero.com/features).
7+
8+
In this guide, we will:
9+
10+
- Run Keycloak with HTTPS using Docker
11+
- Configure a Keycloak client for ASP.NET Zero
12+
- Enable OpenID Connect login
13+
- Perform login & logout operations (ASP.NET Zero + Keycloak)
14+
15+
Let’s start;
16+
17+
## 1. Download and Run ASP.NET Zero
18+
19+
Follow ASP.NET Zero's [Getting Started](https://docs.aspnetzero.com/aspnet-core-mvc/latest/Getting-Started-Core) document to create and run your project. In this blog post, we will be using ASP.NET Core & MVC version, so please be sure to select this version.
20+
21+
## 2. Running Keycloak with HTTPS
22+
23+
We will run Keycloak in Docker using HTTPS. This requires generating a PKCS12 keystore first. To do this, go to `docker` folder in your project and create a folder named `keycloack`.
24+
25+
### 🔹 Generate `server.keystore`
26+
27+
Run this in PowerShell or CMD in `docker\keycloack` we just created above:
28+
29+
```bash
30+
keytool -genkeypair ^
31+
-alias keycloak ^
32+
-keyalg RSA ^
33+
-keysize 2048 ^
34+
-storetype PKCS12 ^
35+
-keystore server.keystore ^
36+
-storepass password ^
37+
-validity 3650
38+
```
39+
40+
After this command, a `server.keystore` file is created in your working directory.
41+
42+
### 🔹 Create `docker-compose.yml`
43+
44+
Create a file named `docker-compose.yml` in the same folder:
45+
46+
```yaml
47+
services:
48+
keycloak:
49+
image: quay.io/keycloak/keycloak:26.0.8
50+
container_name: keycloak
51+
command:
52+
- start
53+
- --https-port=8443
54+
- --http-enabled=false
55+
- --hostname=localhost
56+
- --hostname-strict=false
57+
- --https-key-store-file=/opt/keycloak/conf/server.keystore
58+
- --https-key-store-password=password
59+
environment:
60+
KC_BOOTSTRAP_ADMIN_USERNAME: admin
61+
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
62+
volumes:
63+
- ./server.keystore:/opt/keycloak/conf/server.keystore
64+
ports:
65+
- "8443:8443"
66+
67+
```
68+
69+
### 🔹 Start Keycloak
70+
71+
In `docker\keycloack` folder, run the command below;
72+
73+
```bash
74+
docker compose up
75+
```
76+
77+
Then browse:
78+
79+
```
80+
https://localhost:8443
81+
```
82+
83+
Login using:
84+
85+
- **Username:** admin
86+
- **Password:** admin
87+
88+
✅ Keycloak shoulw be running with HTTPS after running this command.
89+
90+
## 3. Configuring Keycloak
91+
92+
Inside the Keycloak admin panel:
93+
94+
1. Go to **Clients**
95+
2. Click **Create client**
96+
97+
Fill the form as shown below:
98+
99+
![Keycloack Client - General Settings](./images/Blog/keycloack-configuration-1.jpg)
100+
101+
![Keycloack Client - Capability Config](./images/Blog/keycloack-configuration-2.jpg)
102+
103+
![Keycloack Client - Login Settings](./images/Blog/keycloack-configuration-3.jpg)
104+
105+
Save the form after filling all the sections. Then go to **Credentials** and copy the **Client Secret** — we will use it in our ASP.NET Zero project.
106+
107+
## ✅ Configuring ASP.NET Zero
108+
109+
### Configure `appsettings.json`
110+
111+
Add/update the OpenId configuration:
112+
113+
```json
114+
"OpenId": {
115+
"IsEnabled": "true",
116+
"Authority": "https://localhost:8443/realms/master",
117+
"ClientId": "aspnetzero",
118+
"ClientSecret": "<CLIENT-SECRET>",
119+
"ValidateIssuer": "false",
120+
"ResponseType": "code",
121+
"ClaimsMapping": [
122+
{
123+
"claim": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
124+
"key": "email"
125+
},
126+
{
127+
"claim": "unique_name",
128+
"key": "preferred_username"
129+
},
130+
{
131+
"claim": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
132+
"key": "sub"
133+
}
134+
]
135+
}
136+
```
137+
138+
Replace `<CLIENT-SECRET>` with the secret copied from Keycloak.
139+
140+
### Enable OpenID Connect login
141+
142+
In `AuthConfigurer.cs`, change OpenIdConnect configuration as shown below:
143+
144+
```csharp
145+
authenticationBuilder.AddOpenIdConnect(options =>
146+
{
147+
options.ClientId = configuration["Authentication:OpenId:ClientId"];
148+
options.Authority = configuration["Authentication:OpenId:Authority"];
149+
options.SignedOutRedirectUri = configuration["App:WebSiteRootAddress"] + "Account/Logout";
150+
options.ResponseType = configuration["Authentication:OpenId:ResponseType"];
151+
options.SaveTokens = true;
152+
153+
options.TokenValidationParameters = new TokenValidationParameters()
154+
{
155+
ValidateIssuer = bool.Parse(configuration["Authentication:OpenId:ValidateIssuer"])
156+
};
157+
158+
options.Events.OnTokenValidated = context =>
159+
{
160+
var jsonClaimMappings = new List<JsonClaimMap>();
161+
configuration.GetSection("Authentication:OpenId:ClaimsMapping").Bind(jsonClaimMappings);
162+
163+
context.AddMappedClaims(jsonClaimMappings);
164+
165+
return Task.FromResult(0);
166+
};
167+
168+
options.BackchannelHttpHandler = new HttpClientHandler
169+
{
170+
ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true
171+
};
172+
173+
var clientSecret = configuration["Authentication:OpenId:ClientSecret"];
174+
if (!clientSecret.IsNullOrEmpty())
175+
{
176+
options.ClientSecret = clientSecret;
177+
}
178+
179+
options.SignedOutCallbackPath = "/signout-callback-oidc";
180+
options.SignedOutRedirectUri = configuration["App:WebSiteRootAddress"];
181+
182+
options.Events = new OpenIdConnectEvents
183+
{
184+
OnRedirectToIdentityProviderForSignOut = ctx =>
185+
{
186+
var logoutUri = $"{options.Authority}/protocol/openid-connect/logout";
187+
188+
var postLogoutUri = options.SignedOutRedirectUri;
189+
if (!string.IsNullOrEmpty(postLogoutUri))
190+
{
191+
logoutUri +=
192+
$"?post_logout_redirect_uri={Uri.EscapeDataString(postLogoutUri)}&client_id={configuration["Authentication:OpenId:ClientId"]}";
193+
}
194+
195+
ctx.Response.Redirect(logoutUri);
196+
ctx.HandleResponse();
197+
return Task.CompletedTask;
198+
}
199+
};
200+
});
201+
```
202+
203+
✅ Login via Keycloak now should work
204+
205+
### Remote logout in `AccountController`
206+
207+
If you also want logged-in user to logout from Keycloak when user logs out from ASP.NET Zero app, modify the Logout action on AccountController as shown below:
208+
209+
```csharp
210+
public async Task<ActionResult> Logout(string returnUrl = "")
211+
{
212+
await _signInManager.SignOutAsync();
213+
var userIdentifier = AbpSession.ToUserIdentifier();
214+
215+
if (userIdentifier != null &&
216+
_settingManager.GetSettingValue<bool>(AppSettings.UserManagement.AllowOneConcurrentLoginPerUser))
217+
{
218+
var user = await _userManager.GetUserAsync(userIdentifier);
219+
await _userManager.UpdateSecurityStampAsync(user);
220+
}
221+
222+
if (!string.IsNullOrEmpty(returnUrl))
223+
{
224+
returnUrl = NormalizeReturnUrl(returnUrl);
225+
return Redirect(returnUrl);
226+
}
227+
228+
return SignOut(
229+
new AuthenticationProperties { RedirectUri = returnUrl },
230+
OpenIdConnectDefaults.AuthenticationScheme
231+
);
232+
}
233+
```
234+
235+
✅ When a user logs out:
236+
- The ASP.NET Zero cookie is removed
237+
- The user is signed out from Keycloak as well
238+
- They are redirected back to the login screen
239+
240+
# ✅ Result
241+
242+
At this point:
243+
244+
✔ Keycloak runs over HTTPS
245+
✔ ASP.NET Zero authenticates users with OpenID Connect
246+
✔ Claims are correctly mapped
247+
✔ Full logout works (Keycloak + ASP.NET Zero)
248+
249+
This integration is ideal for enterprise projects requiring centralized identity, SSO, or federation with external providers like AD FS, Azure AD, Google, etc.
250+

0 commit comments

Comments
 (0)