IdentityServer4 redirects to Logout page instead of PostLogoutRedirectUri

Viewed 521

I created AspNetCore 3.1 Project and added IdentityServer4 for SSO (added 'Microsoft.AspNetCore.ApiAuthorization.IdentityServer' package). Sig-nin works fine, but logout doesn't.

In Startup.cs I have the following configuration for IdentityServer :

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddIdentityServer()
          .AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
                { ...
                    var client = new Client
                    {
                        ClientName = "ssotestclient",
                        ClientId = "ssotestclient",
                        ClientSecrets = { new Secret("somesecret".Sha256()) },
                        AllowedGrantTypes = GrantTypes.Code.Union(GrantTypes.ResourceOwnerPasswordAndClientCredentials).ToArray(),
                        RequirePkce = false,
                        RequireClientSecret = false,
                        AllowOfflineAccess = false,
                        AlwaysSendClientClaims = true,
                        UpdateAccessTokenClaimsOnRefresh = true,
                        AlwaysIncludeUserClaimsInIdToken = true,
                        AllowedScopes = new List<string>
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Email,
                            IdentityServerConstants.StandardScopes.Profile,
                            IdentityServerConstants.StandardScopes.OfflineAccess
                        },
                        RequireConsent = false,
                        RedirectUris = {"https://mytestsite.local/signin-oidc" },
                        PostLogoutRedirectUris = {"https://mytestsite.local/signout-callback-oidc"}
                    }
                    options.Clients.Add(client);
                 });

The client Website is an AspNetCore MVC project with 'Microsoft.AspNetCore.Authentication.OpenIdConnect' package. Client initialization in Startup.cs

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(options =>
                {
                    options.DefaultScheme = "Cookies";
                    options.DefaultChallengeScheme = "oidc";
                })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.Authority = "https://myssoserver.local";
                options.RequireHttpsMetadata = false;
                HttpClientHandler handler = new HttpClientHandler();
                handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
                options.BackchannelHttpHandler = handler;
                options.ClientId = "ssotestclient";
                options.ClientSecret = "secret";
                options.ResponseType = "code";
                options.UsePkce = true;
                options.Scope.Add("email");
                options.Scope.Add("profile");
                options.SaveTokens = true;
            });
            services.AddAuthorization();
            services.AddRazorPages();
            services.AddControllers();
        }

Logout button on the client website has the following code :

        public async Task OnPostAsync(string returnUrl = null)
        {
            await HttpContext.SignOutAsync("Cookies");
            await HttpContext.SignOutAsync("oidc");
        }

After this the browser is redirected to SSO server with the following location:

https://myssoserver.local/connect/endsession?post_logout_redirect_uri=https%3A%2F%2Fmytestsite.local%2Fsignout-callback-oidc&id_token_hint=<token>&state=<state>&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=5.5.0.0

Actual values of token and state are trimmed from this post because they are too long.

As you can see the post_logout_redirect_uri, id_token_hint and state parameters are passed to the server endsession endpoint. And on the SSO server side I see the message that it has passed validation:

info: IdentityServer4.Validation.EndSessionRequestValidator[0]
      End session request validation success
      {
        "ClientId": "sso_test_client",
        "ClientName": "sso_test_client",
        "SubjectId": "f3693d8c-6095-4f1a-9f8f-bdc7440e9395",
        "PostLogOutUri": "https://mytestsite.local/signout-callback-oidc",
        "State": "<state>",
        "Raw": {
          "post_logout_redirect_uri": "https://mytestsite.local/signout-callback-oidc",
          "id_token_hint": "***REDACTED***",
          "state": "<state>",
          "x-client-SKU": "ID_NETSTANDARD2_0",
          "x-client-ver": "5.5.0.0"
        }
      }

However after this request the browser receives 302 redirect to https://myssoserver.local/Identity/Account/Logout page instead of provided post_logout_redirect_uri. And actual logout doesn't happen, because only OnGet() handler is called that does nothing

Could not find similar issue on the web.

What could be wrong? Why do I get redirected to the Logout page instead of a callback uri? I searched through the project code and could not find any reference with the 'Logout' word apart from Logout page itself

1 Answers

One thought is that you need to set the LogoutPath.

.AddCookie(options => { options.LogoutPath = "/User/Logout"; })

LogoutPath is a security feature, just as this picture from one of my training classes shows:

enter image description here

Related