How to Implement Keycloak Authentication in a .NET Core Application

Ahmed Gado
5 min readApr 15, 2023

--

Keycolak Logo

Authentication is a crucial aspect of building secure web applications. One popular solution for authentication is Keycloak, an open-source identity and access management system that provides authentication, authorization, and single sign-on capabilities. In this article, we will show you how to implement Keycloak authentication in a .NET Core application.

Prerequisites

Before we begin, you should have the following:

  • A Keycloak server installed and configured. If you don’t have a Keycloak server set up, you can follow the instructions in the official Keycloak documentation.
  • A .NET Core application set up with basic authentication.

Step 1: Configure Keycloak Client Settings

Before you can authenticate against Keycloak, you need to create a client in Keycloak and configure its settings. To do this, log in to your Keycloak server’s administration console, create a new client, and set its Access Type to confidential. Then, configure the client's Redirect URIs and Web Origins to match your application's URLs. Finally, make a note of the client's Client ID and Client Secret, which you will need later.

Step 2: Add the Package

In your .NET Core application, add the Microsoft.AspNetCore.Authentication.OpenIdConnect package to your project via NuGet. This package provides the middleware to handle OpenID Connect authentication with Keycloak.

Step 3: Configure Authentication Middleware

In the ConfigureServices method of your Startup.cs file, add the following code to configure the OpenID Connect authentication middleware:

services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/Account/Login";
})
.AddOpenIdConnect(options =>
{
options.Authority = "https://your-keycloak-server/auth/realms/your-realm-name";
options.ClientId = "your-client-id";
options.ClientSecret = "your-client-secret";
options.ResponseType = "code";
options.SaveTokens = true;
options.Scope.Add("openid");
options.CallbackPath = "/login-callback"; // Update callback path
options.SignedOutCallbackPath = "/logout-callback"; // Update signout callback path
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "preferred_username",
RoleClaimType = "roles"
};
});

Here, you need to replace the values for Authority, ClientId, and ClientSecret with the appropriate values for your Keycloak server and client. Additionally, you may want to customize the ResponseType, Scope, and TokenValidationParameters settings to fit your specific requirements.

Step 4: Configure Authentication Middleware in Configure Method

In the Configure method of your Startup.cs file, add the following code to enable the authentication middleware:

app.UseAuthentication();
app.UseAuthorization();

Step 5: Protect Your Application Endpoints

To require authentication for certain endpoints in your application, you can use the [Authorize] attribute. For example:

[Authorize(Roles = "admin")]
public IActionResult AdminPanel()
{
return View();
}

Here, the Roles parameter specifies the roles that are authorized to access the endpoint.

Step 6: Handle Authentication Callbacks

When a user logs in via Keycloak, Keycloak will redirect the user back to your application with an authentication code. Your application must handle this redirect and exchange the code for an access token.

To do this handle the authentication callback in your AccountController.cs file:

public async Task<IActionResult> LoginCallback()
{
var authResult = await HttpContext.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
if (authResult?.Succeeded != true)
{
// Handle failed authentication
return RedirectToAction("Login");
}

// Get the access token and refresh token
var accessToken = authResult.Properties.GetTokenValue("access_token");
var refreshToken = authResult.Properties.GetTokenValue("refresh_token");

// Save the tokens to the user's session or database
HttpContext.Session.SetString("access_token", accessToken);
HttpContext.Session.SetString("refresh_token", refreshToken);

// Redirect the user to the desired page
return RedirectToAction("Index");
}

Here, the LoginCallback method is called when the user is redirected back to your application after logging in via Keycloak. The method uses the AuthenticateAsync method to retrieve the authentication result from the OpenID Connect middleware. If authentication succeeded, the method retrieves the access token and refresh token from the authentication result's properties, and saves them to the user's session or database for later use. Finally, the method redirects the user to the desired page, such as the home page of your application.

And to configure the authentication middleware to work with a callback path in a .NET Core application, you need to specify the proper callback paths and routes in your application’s startup configuration.

Here’s how you can configure the authentication middleware to work with a callback path:

  • In your Startup.cs file, configure the authentication middleware with the appropriate callback paths. You should include a specific path where Keycloak will redirect users after authentication.
public void ConfigureServices(IServiceCollection services)
{
// ...

services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/Account/Login";
})
.AddOpenIdConnect(options =>
{
options.Authority = "https://your-keycloak-server/auth/realms/your-realm-name";
options.ClientId = "your-client-id";
options.ClientSecret = "your-client-secret";
options.ResponseType = "code";
options.SaveTokens = true;
options.Scope.Add("openid");
options.CallbackPath = "/login-callback"; // Update callback path
options.SignedOutCallbackPath = "/logout-callback"; // Update signout callback path
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "preferred_username",
RoleClaimType = "roles"
};
});
}

public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseAuthorization();

// ...
}
  • In the above code, options.CallbackPath specifies the callback path where Keycloak will redirect users after authentication. You can customize this path as needed. Similarly, options.SignedOutCallbackPath is used to specify the callback path for sign-out.
  • Be sure to add the corresponding callback routes in the Startup.cs file:
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseAuthorization();

// Add routes for callback handling
app.Map("/login-callback", loginCallbackApp =>
{
loginCallbackApp.Run(async context =>
{
// Handle the callback from Keycloak after successful authentication
await context.Response.WriteAsync("Authentication successful");
});
});

app.Map("/logout-callback", logoutCallbackApp =>
{
logoutCallbackApp.Run(async context =>
{
// Handle the callback from Keycloak after sign-out
await context.Response.WriteAsync("Sign-out successful");
});
});

// ...
}
  • These callback paths should match the values you specified in the authentication middleware configuration.

Note: that you will also need to add a route to your Startup.cs file to handle the authentication callback. Here's an example:

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");

// Add route for Keycloak authentication callback
endpoints.MapControllerRoute(
name: "login-callback",
pattern: "login-callback",
defaults: new { controller = "Account", action = "LoginCallback" });
});

Here, the MapControllerRoute method adds a route to handle requests to the /login-callback URL. When a user logs in via Keycloak, Keycloak will redirect the user to this URL with an authentication code, which is then handled by the LoginCallback method.

At the End keep in mind

The code examples I provided should work as long as you have properly configured Keycloak and the OpenID Connect middleware in your .NET Core application. However, there may be some issues that you could encounter depending on your specific implementation. Here are a few things to keep in mind:

  1. The LoginCallback method assumes that the access token and refresh token are stored in the Properties object of the authentication result. However, this may not always be the case depending on your Keycloak configuration. You may need to adjust the code to retrieve the tokens from a different location if necessary.
  2. The HttpContext.Session object used to store the tokens assumes that you are using session-based authentication. If you are using a different authentication method, such as JWT tokens, you may need to store the tokens in a different location.
  3. The Startup.cs code assumes that you are using the default OpenIdConnectDefaults.AuthenticationScheme scheme for authentication. If you are using a different authentication scheme, you will need to adjust the code accordingly.
  4. You should also be aware of security concerns when handling tokens in your application. For example, you should ensure that tokens are properly secured and encrypted when stored in session or database, and that they are refreshed or expired when necessary to prevent unauthorized access.

--

--