Is there a way to execute a single-sign-out for clients only using IdentityServer4? I have no problem executing single-sign-out for clients and IdentityServer using the endsession
endpoint. What I would like to do, however, is provide a way to force all clients to re-authenticate upon next request (to get fresh claims) but not force the user to re-enter credentials.
The use case is for the user to edit profile information which is stored in claims. For example, their name. When the user submits a change to this information, all other clients need to be made aware that the claims they currently have are no longer valid. This can be achieved by signing the user out completely, but then the user must re-enter their id and password.
Looking at the flow, I guess what I'm trying to do is execute the internal EndSessionCallbackEndpoint
directly, without removing the authentication cookie for IdentityServer itself.
Below is a solution that is working, but this really feels like I'm abusing the system. If anyone has a "standard" way to provide the expected functionality, please let me know.
This solution alters the Logout
method to "sniff" for a magic PostLogoutRedirectUri
and to skip the deletion of the local authentication cookie. Obviously not particularly scalable or elegant.
[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);
// Special post-logout URL that should only log out clients, but keep the local authentication cookie.
bool clientsOnly = !string.IsNullOrEmpty(vm.PostLogoutRedirectUri) && vm.PostLogoutRedirectUri.StartsWith("https://example.com/EditProfile");
if (User?.Identity.IsAuthenticated == true && !clientsOnly)
{
// delete local authentication cookie
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
// check if we need to trigger sign-out at an upstream identity provider
if (vm.TriggerExternalSignout)
{
// build a return URL so the upstream provider will redirect back to us after the
// user has logged out. this allows us to then complete our single sign-out processing.
string url = Url.Action("Logout", new { logoutId = vm.LogoutId });
// this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url }, vm.ExternalAuthenticationScheme);
}
return View("LoggedOut", vm);
}