feat(identity): pluggable identity providers — Keycloak + OpenIddict#216
Merged
Conversation
Support both Keycloak and OpenIddict as identity providers via a single `Identity:Provider` configuration key. Both modules coexist in the same binary; only the configured one activates at startup. - Add Identity.Contracts module with provider-agnostic ISessionContracts, IIdentityProvider, SessionDto, and RevokeSessionResult - Add Keycloak module with OIDC auth code flow, JWT Bearer validation, SmartAuth policy scheme, Admin REST API client, and claims transformation - Add JIT shadow user provisioning (Keycloak sub → local ApplicationUser) - Add Users module dual-mode: local (UserManager) vs external (direct EF) - Add Aspire AppHost Keycloak container with realm import and test users - Refactor Admin module to depend on Identity.Contracts instead of OpenIddict - Add OpenIddict stub adapter for Keycloak mode compatibility
Deploying simplemodule-website with
|
| Latest commit: |
6455a8d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://8490fb80.simplemodule-website.pages.dev |
| Branch Preview URL: | https://feature-keycloak-identity.simplemodule-website.pages.dev |
The restore stage explicitly copies each module's .csproj for layer caching. The new Identity.Contracts, Keycloak.Contracts, and Keycloak projects were missing, causing dotnet restore to fail in CI.
Three issues prevented roles from working in Keycloak mode: 1. OIDC RoleClaimType was set to "roles" but role claims were added as ClaimTypes.Role — IsInRole() never matched. Fixed by setting RoleClaimType to ClaimTypes.Role. 2. realm_access roles were only parsed in ClaimsTransformation (runs per-request) but not at OIDC token validation time. Added KeycloakOidcEvents.OnTokenValidated to extract roles from the realm_access JWT claim and bake them into the cookie identity. 3. Keycloak roles had no local ApplicationRole records, so PermissionClaimsTransformation couldn't resolve permissions. Extended KeycloakUserSyncService to JIT-create local roles and assign them to shadow users.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Identity:Providerconfig key — supports both OpenIddict (default, self-hosted) and Keycloak (external IdP) in the same binaryISessionContracts,IIdentityProvider,SessionDto, andRevokeSessionResult— all consuming modules depend on contracts, not a specific provider--launch-profile keycloakIdentity.Contractsinstead ofOpenIddict.Contractsfor session managementArchitecture
How to switch providers
Screenshots — OpenIddict mode (default)
Landing Page
Login Page
Authenticated Dashboard
Admin Hub
Admin Users
User Sessions (ISessionContracts)
Screenshots — Keycloak OIDC flow
1. Click "Log in" → Redirects to Keycloak
2. Enter Keycloak credentials
3. OIDC callback → Authenticated Dashboard (Admin link visible)
4. Admin Hub (Keycloak mode — roles synced from Keycloak)
5. Admin Users (JIT-provisioned user visible)
6. User dropdown
Test plan
dotnet run --project SimpleModule.AppHost --launch-profile keycloakand verifies Keycloak login flow