have a Blazor Server application configured with OpenID Connect (OIDC) authentication using Keycloak. Login works fine and I can authenticate successfully. However, when I log out, I get redirected to the Keycloak logout page but upon returning to my Blazor application, I find that I'm still logged in, even though the Keycloak session is expired.
Here are the details of my setup:Program.cs
using Microsoft.AspNetCore.Authentication;using Microsoft.AspNetCore.Authentication.Cookies;using Microsoft.AspNetCore.Authentication.OpenIdConnect;using Microsoft.AspNetCore.Authorization;using Microsoft.IdentityModel.Protocols.OpenIdConnect;using Microsoft.IdentityModel.Tokens;using System.IdentityModel.Tokens.Jwt;var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddRazorPages();builder.Services.AddServerSideBlazor();builder.Services.AddHttpContextAccessor();builder.Services.AddSingleton<LogoutService>();// Configure loggingbuilder.Logging.ClearProviders();builder.Logging.AddConsole();// Configure OIDC authenticationvar oidcSettings = builder.Configuration.GetSection("OIDC");builder.Services.AddAuthentication(options =>{ options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;}).AddCookie(options =>{ options.Events.OnSigningOut = async e => { e.HttpContext.Response.Cookies.Delete(".AspNetCore.Cookies"); await Task.CompletedTask; };}).AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>{ options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Scope.Add(OpenIdConnectScope.OfflineAccess); options.MetadataAddress = "https://keycloak.example.com/realms/myrealm/.well-known/openid-configuration"; options.Authority = oidcSettings["Authority"]; options.ClientId = oidcSettings["ClientId"]; options.ClientSecret = oidcSettings["ClientSecret"]; options.ResponseType = OpenIdConnectResponseType.Code; options.SaveTokens = false; options.GetClaimsFromUserInfoEndpoint = true; options.CallbackPath = new PathString("/signin-oidc"); options.SignedOutCallbackPath = new PathString("/signout-callback-oidc"); options.RemoteSignOutPath = new PathString("/signout-oidc"); options.SignOutScheme = OpenIdConnectDefaults.AuthenticationScheme; options.MapInboundClaims = false; options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name; options.TokenValidationParameters.RoleClaimType = "role"; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = oidcSettings["Authority"], ValidateAudience = true, ValidAudience = oidcSettings["ClientId"], ValidateLifetime = true }; options.Scope.Add("profile"); options.Scope.Add("email");});builder.Services.AddAuthorization(options =>{ options.FallbackPolicy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.AddPolicy("AnonymousPolicy", policy => policy.RequireAssertion(_ => true));});builder.Services.AddControllersWithViews();var app = builder.Build();if (!app.Environment.IsDevelopment()){ app.UseExceptionHandler("/Error"); app.UseHsts();}app.UseHttpsRedirection();app.UseStaticFiles();app.UseRouting();app.UseAuthentication();app.UseAuthorization();app.MapBlazorHub();app.MapFallbackToPage("/_Host");app.Run();appsettings.json
{"Logging": {"LogLevel": {"Default": "Debug","Microsoft": "Debug","Microsoft.AspNetCore": "Debug" } },"OIDC": {"Authority": "https://keycloak.example.com/realms/myrealm","ClientId": "myclientid","ClientSecret": "myclientsecret","CallbackPath": "/signin-oidc","PostLogoutRedirectUri": "https://localhost:7029/","SignedOutCallbackPath": "/signout-callback-oidc","SignOutPath": "/signout-oidc" }}Razor Page
@page "/counter"@using Microsoft.AspNetCore.Authentication.Cookies@using Microsoft.AspNetCore.Authentication.OpenIdConnect<PageTitle>Index</PageTitle>@inject NavigationManager Navigation@inject IConfiguration Configuration@inject IHttpContextAccessor HttpContextAccessor<AuthorizeView><Authorized><button @onclick="Logout">Logout</button></Authorized><NotAuthorized><button @onclick="Login">Login</button></NotAuthorized></AuthorizeView>@code { private void Login() { Navigation.NavigateTo("https://keycloak.example.com/realms/myrealm/protocol/openid-connect/auth?client_id=myclientid&redirect_uri=https://localhost:7029/signin-oidc&response_type=code&scope=openid"); } private void Logout() { var authority = Configuration["OIDC:Authority"]; var postLogoutRedirectUri = Configuration["OIDC:PostLogoutRedirectUri"]; var logoutUrl = $"{authority}/protocol/openid-connect/logout?client_id=myclientid&post_logout_redirect_uri={Navigation.ToAbsoluteUri("/")}"; Navigation.NavigateTo(logoutUrl, true); }}Problem Description:
Login works and redirects successfully to the application.Logging out redirects to the Keycloak logout page, but when I return to the application, I'm still logged in.The session in Keycloak is expired but the Blazor application still recognizes the user as logged in.