To properly implement the logout mechanism in your .NET application using Keycloak as the OpenID Connect provider, you need to ensure that the id_token_hint parameter is included in the logout request. This parameter is used by Keycloak to identify the user session that needs to be terminated.
Here's how to achieve this:
Save the ID Token: Ensure that the ID token is saved when the user logs in. This can be done by setting options.SaveTokens = true in your OpenIdConnect configuration, which you have already done.
Retrieve the ID Token: When the user logs out, retrieve the saved ID token from the authentication properties.
Include the ID Token in the Logout Request: Pass the ID token as the id_token_hint parameter in the logout request to Keycloak.
Here's how it looks:
Step 1: Modify the OpenIdConnect Configuration Ensure that the ID token is saved by setting options.SaveTokens = true:
builder.Services.AddAuthentication(oidcScheme)
.AddKeycloakOpenIdConnect("keycloak", realm: "WeatherShop", oidcScheme, options =>
{
options.ClientId = "WeatherWeb";
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("weather:all");
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
options.SaveTokens = true;
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme);
Step 2: Retrieve the ID Token and Include it in the Logout Request Modify the logout endpoint to retrieve the ID token and include it in the logout request:
internal static IEndpointConventionBuilder MapLoginAndLogout(this IEndpointRouteBuilder endpoints)
{
var group = endpoints.MapGroup("authentication");
// This redirects the user to the Keycloak login page and, after successful login, redirects them to the home page.
group.MapGet("/login", () => TypedResults.Challenge(new AuthenticationProperties { RedirectUri = "/" }))
.AllowAnonymous();
// This logs the user out of the application and redirects them to the home page.
group.MapGet("/logout", async (HttpContext context) =>
{
var authResult = await context.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var idToken = authResult.Properties.GetTokenValue("id_token");
if (idToken == null)
{
// Handle the case where the ID token is not found
return Results.BadRequest("ID token not found.");
}
var logoutProperties = new AuthenticationProperties
{
RedirectUri = "/",
Items =
{
{ "id_token_hint", idToken }
}
};
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Results.SignOut(logoutProperties, [CookieAuthenticationDefaults.AuthenticationScheme, OpenIdConnectDefaults.AuthenticationScheme]);
});
return group;
}
Step 3: Ensure that your Keycloak client configuration includes the correct post-logout redirect URI:
{
"id" : "016c17d1-8e0f-4a67-9116-86b4691ba99c",
"clientId" : "WeatherWeb",
"name" : "",
"description" : "",
"rootUrl" : "",
"adminUrl" : "",
"baseUrl" : "",
"surrogateAuthRequired" : false,
"enabled" : true,
"alwaysDisplayInConsole" : false,
"clientAuthenticatorType" : "client-secret",
"redirectUris" : [ "https://localhost:7058/signin-oidc" ],
"webOrigins" : [ "https://localhost:7058" ],
"notBefore" : 0,
"bearerOnly" : false,
"consentRequired" : false,
"standardFlowEnabled" : true,
"implicitFlowEnabled" : false,
"directAccessGrantsEnabled" : false,
"serviceAccountsEnabled" : false,
"publicClient" : true,
"frontchannelLogout" : true,
"protocol" : "openid-connect",
"attributes" : {
"oidc.ciba.grant.enabled" : "false",
"post.logout.redirect.uris" : "https://localhost:7058/signout-callback-oidc",
"oauth2.device.authorization.grant.enabled" : "false",
"backchannel.logout.session.required" : "true",
"backchannel.logout.revoke.offline.tokens" : "false"
},
"authenticationFlowBindingOverrides" : { },
"fullScopeAllowed" : true,
"nodeReRegistrationTimeout" : -1,
"defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ],
"optionalClientScopes" : [ "address", "phone", "offline_access", "weather:all", "microprofile-jwt" ]
}
By following these steps, you should be able to properly implement the logout mechanism in your .NET application using Keycloak as the OpenID Connect provider. The id_token_hint parameter will be included in the logout request, allowing Keycloak to correctly identify and terminate the user session.