Search code examples
asp.net-coreopenid-connect

ASP.NET Core: OpenIDConnect: Keycloak: Logout: not redirecting to keycloak login page


I am implementing openidconnect authentication using keycloak server in my asp.net core application. The login works ok, but I'm not able to implement logout. The behavior is that it takes me to the home page of my web app; instead it should take me to the keycloak login page. Below is my code:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
                {
                    // Store the session to cookies
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    // OpenId authentication
                    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                })
                .AddCookie(cookie =>
                {
                    cookie.Cookie.Name = "keycloak.cookie";
                    cookie.Cookie.MaxAge = TimeSpan.FromMinutes(60);
                    cookie.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
                    cookie.SlidingExpiration = true;
                })
                .AddOpenIdConnect(options =>
                {
                    
                    options.Authority = Configuration.GetSection("Keycloak")["Authority"];
                    //Keycloak client ID
                    options.ClientId = Configuration.GetSection("Keycloak")["ClientId"];
                    //Keycloak client secret
                    options.ClientSecret = Configuration.GetSection("Keycloak")["ClientSecret"];
                    
                    // For testing we disable https (should be true for production)
                    options.RequireHttpsMetadata = false;
                    options.SaveTokens = true;
                    options.GetClaimsFromUserInfoEndpoint = true;
                    // OpenID flow to use
                    options.ResponseType = OpenIdConnectResponseType.CodeIdToken;

                    options.Events.OnSignedOutCallbackRedirect += context =>
                    {
                        context.Response.Redirect(context.Options.SignedOutRedirectUri);
                        context.HandleResponse();

                        return Task.CompletedTask;
                    };

                });

}

Index.shtml:

<a class="nav-link text-light" asp-page-handler="Logout" asp-page="/Pages/Index">Sign out</a>

Index.cshtml.cs:

public IActionResult Logout()
        {
            
            return new SignOutResult(
                new[] {
                OpenIdConnectDefaults.AuthenticationScheme,
                CookieAuthenticationDefaults.AuthenticationScheme
                });            
        }

Solution

  • You are not supposed to return anything from the Logout method, because SignOutAsync genereates its own response.

    So, this is how I do logouts in my applications:

        /// <summary>
        /// Do the logout
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task Logout()
        {
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
    
            //Important, this method should never return anything.
        }