Post Impatica
Post Impatica

Reputation: 16433

IDSRV4 Logout - obtain ClientId dynamically

There are many examples on how to clear persisted grants during logout using IdentityServer4 but they all show statically setting the ClientId. Anyone know how to dynamically obtain the ClientId because I plan to use this IdentityServer with several different clients. Here is the code found here you usually find, look at the second-to-last line:

[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
public async Task<IActionResult> Logout(LogoutViewModel model)
{
    var idp = User?.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
    var subjectId = HttpContext.User.Identity.GetSubjectId();

    if (idp != null && idp != IdentityServerConstants.LocalIdentityProvider)
    {
        if (model.LogoutId == null)
        {
            // if there's no current logout context, we need to create one
            // this captures necessary info from the current logged in user
            // before we signout and redirect away to the external IdP for signout
            model.LogoutId = await _interaction.CreateLogoutContextAsync();
        }

        string url = "/Account/Logout?logoutId=" + model.LogoutId;
        try
        {
            // hack: try/catch to handle social providers that throw
            await HttpContext.Authentication.SignOutAsync(idp, new AuthenticationProperties { RedirectUri = url });
        }
            catch(NotSupportedException)
        {
        }
    }

    // delete authentication cookie
    await _signInManager.SignOutAsync();

    // set this so UI rendering sees an anonymous user
    HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity());

    // get context information (client name, post logout redirect URI and iframe for federated signout)
    var logout = await _interaction.GetLogoutContextAsync(model.LogoutId);

    var vm = new LoggedOutViewModel
    {
        PostLogoutRedirectUri = logout?.PostLogoutRedirectUri,
        ClientName = logout?.ClientId,
        SignOutIframeUrl = logout?.SignOutIFrameUrl
    };

    await _persistedGrantService.RemoveAllGrantsAsync(subjectId, "angular2client");

    return Redirect(Config.HOST_URL + "/index.html");
}

Upvotes: 1

Views: 1272

Answers (1)

Post Impatica
Post Impatica

Reputation: 16433

This is what I ended up using:

    /// <summary>
    /// Handle logout page postback
    /// </summary>
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Logout(LogoutInputModel model)
    {
        var vm = await _account.BuildLoggedOutViewModelAsync(model.LogoutId);

        if (vm.TriggerExternalSignout)
        {
            string url = Url.Action("Logout", new { logoutId = vm.LogoutId });
            try
            {
                // hack: try/catch to handle social providers that throw
                await HttpContext.Authentication.SignOutAsync(vm.ExternalAuthenticationScheme,
                    new AuthenticationProperties { RedirectUri = url });
            }
            catch (NotSupportedException) // this is for the external providers that don't have signout
            {
            }
            catch (InvalidOperationException) // this is for Windows/Negotiate
            {
            }
        }

        // delete local authentication cookie
        await HttpContext.Authentication.SignOutAsync();

        var user = await HttpContext.GetIdentityServerUserAsync();
        if (user != null)
        {
            await _persistedGrantService.RemoveAllGrantsAsync(user.GetSubjectId(), vm.ClientName);
            await _events.RaiseAsync(new UserLogoutSuccessEvent(user.GetSubjectId(), user.GetName()));                
        }

        return View("LoggedOut", vm);
    }

Upvotes: 1

Related Questions