DuendeSoftware / Support

Support for Duende Software products
20 stars 0 forks source link

Logout Issue OWIN MVC/CORS issue #1269

Closed MH61Aus closed 2 months ago

MH61Aus commented 2 months ago

Which version of Duende IdentityServer are you using?

7

Which version of .NET are you using?

8

Question how to signout from OWIN MVC with js

I'm in the process of connecting an old app of ours to identity server. It is dotnet 4.8, using the setup from your OWIN MVC sample. The app uses a Sencha ExtJS frontend that is rendered via MVC. I felt this was trivial as everything hits the client controllers before hitting any other endpoints (i.e. there's not going to be any Web API calls being made from the JS - they'd only be made from the client controllers, so secrets, etc are confidential and as far as I comprehend there's no need for a BFF).

However, when trying to do logout I've found there's some CORS and redirect issues.

Basically, the logout button hits a controller on the client:

    Logout: function () {
        fetch('/Oidc/LogoutOidc').then(function (response) {
            console.log(response);
        }, { method: 'POST', redirect: 'follow', mode: 'no-cors', credentials: 'include' });
    },

Which hits the controller action

    public class OidcController : Controller
    {
        public ActionResult LogoutOidc()
        {
            if (Request.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.SignOut("oidc", CookieAuthenticationDefaults.AuthenticationType);
            }
            return Json(new
            {
                success = true
            });
        }
    }

But, I was finding the problem here compared to the MVC sample, is that because the JS was the orginator of the call to the controller, when it tries to hit the end session endpoint I get a CORS issue.

I tried to get arround this by adding

AllowedCorsOrigins = { "https://localhost:myport" },

to the client config, but then i found that endsession wasn't in the CorsPaths, so I also added

options.Cors.CorsPaths.Add(new PathString(ProtocolRoutePaths.EndSession.EnsureLeadingSlash()));

to startup

But I still got CORS issues for the Account/Logout and Account/LoggedOut pages, so I created my own Cors Policy:

services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{
    builder.WithOrigins("https://localhost:myPort")
           .AllowAnyMethod()
           .AllowAnyHeader()
           .AllowCredentials();
}));

And I think I'm adding it in the right place in the pipeline

    app.UseIdentityServer();

    app.UseCors("MyPolicy");

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

It does hit Account/Logout, but if (User?.Identity.IsAuthenticated == true) does not pass - the user is no longer authenticated.

I thought this may be something to do with the SetIdTokenHintOnLogout code setup in the sample - I've got all this code in mine, and it seems to be setting the IdTokenHint properly.

If you can help point me in the right direction or let me know if I've misunderstood anything here, I'd really appreciate it.

AndersAbel commented 2 months ago

If you initiate a logout using Owin that cannot be handled in a fetch call. The OIDC logout will result in a redirect being issued to IdentityServer. That need to be processed by the users browser. Instead of using fetch you should just redirect the entire browser window to the logout endpoint.

And you are right, you do not need our BFF implementation in the application you describe because it already follows the BFF pattern when the API calls are done from the server side.

RolandGuijt commented 2 months ago

@MH61Aus Did Anders' comment help you? Anything to add? If not I'd like to close the issue.

MH61Aus commented 2 months ago

sorry, I forgot to follow up. Everything seems to be working now. the fetch was replaced with location.href = '/Oidc/LogoutOidc';

With it redirecting to the controller I no longer needed to make all the CORS changes either.