2
votes

I'm looking at how to disconnect the user currently logged on the mvc client (e.g. http://localhost:5001), when that user performs logout on identity server's deployment (e.g. http://localhost:5000)

I understand there's an implementation of OAuth2 in identityserver4 that does just that (https://openid.net/specs/openid-connect-backchannel-1_0.html and https://openid.net/specs/openid-connect-frontchannel-1_0.html)

Luckily for me, Brock Allen just pushed a change in the samples less than a day ago: https://github.com/IdentityServer/IdentityServer4.Samples/issues/197

However the sample is either incomplete at this point, or I'm missing something.

on my server, I'm setting the value of FrontChannelLogoutUrl to http://localhost:5001/frontchannello, and I added that piece of code to my mvc client (basically stolen from the sample):

[HttpGet("frontChannello")]
public IActionResult FrontChannelLogout(string sid)
{
    if (User.Identity.IsAuthenticated)
    {
        var currentSid = User.FindFirst("sid")?.Value ?? "";
        if (string.Equals(currentSid, sid, StringComparison.Ordinal))
        {
            //await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return new SignOutResult(new[] { "Cookies", "oidc" });
        }
    }

    return NoContent();
}

That code never gets called.

So my question is: should I use backchannel or frontchannel; and, how to implement it

2

2 Answers

2
votes

The Identity server 4 documentation describes well how front-channel logout should be implemented. Look for the Quickstart 8_AspnetIdentity as it provides most of the code required for the implementation.

Some highlights of the code required in the identity server :

In the AccountController.cs, the Logout function builds a LoggedOutViewModel and returns a LoggedOut view.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout(LogoutInputModel model)
{
   // build a model so the logged out page knows what to display
   var vm = await BuildLoggedOutViewModelAsync(model.LogoutId);
   ...
   return View("LoggedOut", vm);
}

The SignOutIframeUrl iframe is served in the LoggedOut.cshtml.

@model LoggedOutViewModel

<div class="page-header logged-out">
   <small>You are now logged out</small>
   ...
   @if (Model.SignOutIframeUrl != null)
   {
       <iframe width="0" height="0" class="signout" src="@Model.SignOutIframeUrl"></iframe>
   }
</div>

What remains to be done is defining the FrontChannelLogoutUri for your each of your clients. That's normally done in the identity server's config.cs

 public static IEnumerable<Client> GetClients()
 {
        return new List<Client>
        {
            // resource owner password grant client
            new Client
            {
                ClientId = "js",
                ClientName = "JavaScript Client",
                AllowedGrantTypes = GrantTypes.Code,
                RequirePkce = true,
                RequireClientSecret = false,

                RedirectUris =           { "http://localhost:5003/callback.html" },
                PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
                FrontChannelLogoutUri = "http://localhost:5003/frontChannello"
1
votes

Ok pretty simple. In your Logout action on the account controller (in idserver), make sure you display the LoggedOut view, which in turn shows the iFrame that calls the callback on the mvc client. Pretty much what the spec are saying.