Implementing Enterprise SSO with Keycloak in ASP.NET Core MVC (.NET 8)
A Practical Implementation Walkthrough
1. Introduction
This article focuses on the practical implementation details of integrating Keycloak Single Sign-On (SSO) into an ASP.NET Core MVC (.NET 8) application.
Rather than covering conceptual SSO fundamentals or step-by-step beginner tutorials, this walkthrough documents a production-oriented integration including authentication flow, logout handling, claim mapping, and architectural decisions that commonly arise in real enterprise systems.
The implementation shown here reflects a common scenario in modern applications: authentication is delegated to a centralized identity provider (Keycloak), while the application remains focused on business logic, authorization boundaries, and maintainable structure.
This article is a continuation of the earlier conceptual discussion on enterprise SSO and now shifts the focus entirely to code-level decisions and structure.
2. Project Structure Overview
To keep the authentication logic clean and maintainable, the solution is intentionally split into two projects.
Web.Core
Web.Core acts as the application’s core layer, containing abstractions and domain structures that are not aware of any external identity provider.
Key responsibilities include:
- Domain models (Entities)
- Request and response contracts
- Repository and service abstractions
- User identity abstraction (ICurrentUser)
This design allows the core layer to remain testable, portable, and reusable, regardless of whether authentication is handled by Keycloak or another identity provider.
Web.Mvc
Web.Mvc is the application entry point and owns all web-specific and authentication concerns.
Key responsibilities include:
- ASP.NET Core MVC setup
- Keycloak authentication configuration
- Claim mapping
- Authorization policies
- UI integration (Bootstrap admin template)
By isolating authentication logic in this layer, the application avoids leaking Keycloak-specific details into domain or service code.
3. Authentication Flow with Keycloak
The authentication flow follows the standard OpenID Connect Authorization Code Flow, with Keycloak acting as the identity provider.
High level flow:
- A user attempts to access a protected MVC route.
- ASP.NET Core redirects the user to Keycloak’s login page.
- The user authenticates using credentials managed entirely by Keycloak.
- Keycloak redirects the user back with an authorization code.
- ASP.NET Core exchanges the code for tokens.
- User claims are mapped and normalized.
From the application’s perspective, authentication becomes a delegated concern. Once the OpenID Connect handshake completes, the MVC application works with a normalized ClaimsPrincipal.
4. Login & Logout Handling
Handling login and logout correctly is one of the most critical and frequently misunderstood parts of implementing Single Sign-On.
In an SSO-enabled system authentication state exists in two places:
- Local application session (ASP.NET Core authentication cookie)
- Identity provider session (Keycloak)
Failing to invalidate both sessions leads to inconsistent behavior such as users being automatically logged back in after logout.
Login Flow
The login flow relies entirely on OpenID Connect and is initiated automatically when a protected route is accessed.
- User accesses protected route
- ASP.NET Core triggers OpenID Connect challenge
- User redirected to Keycloak login
- User authenticates
- User redirected back
- Authentication cookie created
- Claims mapped and normalized
Logout
A common mistake is to clear only the local authentication cookie. This does not terminate the Keycloak session.
Proper logout requires invalidating both sessions.
5. Claim Mapping Strategy
When integrating with an external identity provider such as Keycloak, the authentication process results in a ClaimsPrincipal populated with provider-specific claims.
Examples include:
preferred_username- roles inside
realm_access
Relying on raw claims throughout the application leads to fragile code and tight coupling to the identity provider.
Why Claim Mapping Is Necessary
- Normalize external claims
- Decouple application from Keycloak
- Centralize identity logic
- Improve maintainability
To address this, the project introduces a dedicated component: KeycloakClaimMapper.
6. Abstracting User Identity (ICurrentUser)
Even with proper claim mapping, directly accessing HttpContext.User throughout the application introduces hidden dependencies.
This implementation introduces an explicit abstraction: ICurrentUser.
Benefits include:
- Centralized identity access
- Improved testability
- Reduced framework coupling
- Future flexibility
7. Integrating the Bootstrap UI
To validate the SSO implementation in a real application environment, the project integrates a lightweight Bootstrap admin template called Crudify Admin.
Repository: Crudify Admin Template
Key characteristics:
- Bootstrap-based layout
- Minimal dependencies
- Reusable structure
- Suitable for admin applications
Conclusion
Integrating Single Sign-On is not just about enabling login. It is about establishing clear identity boundaries across the system.
By combining Keycloak with ASP.NET Core MVC and applying deliberate architectural decisions, this implementation achieves:
- Centralized authentication
- Predictable logout behavior
- Clean separation of concerns
- A maintainable identity model
Source Code
GitHub Repository: ASP.NET Core Keycloak SSO MVC