17

I am using IdenetityServer4 and Redirecting to MVC client after Logout is not working. Following is my MVC client controller Logout action:

public async Task Logout()
{
    await HttpContext.Authentication.SignOutAsync("Cookies");
    await HttpContext.Authentication.SignOutAsync("oidc");
}

Following is identity server 4 Host config file.

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        // other clients omitted...

        // OpenID Connect implicit flow client (MVC)
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Implicit,

            // where to redirect to after login
            RedirectUris = { "http://localhost:58422/signin-oidc" },

            // where to redirect to after logout
            PostLogoutRedirectUris = { "http://localhost:58422/signout-callback-oidc" },

            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile
            }
        }
    };
} 

I want user to be redirect back to MVC client after getting Logged out from IdentityServer. Right now user has to click link show in below image to redirected back to MVC site but i think user should be automatically redirected back to MVC client.

enter image description here

MJK
  • 3,434
  • 3
  • 32
  • 55
Sandeep
  • 1,182
  • 3
  • 11
  • 26

3 Answers3

44

There is no problem in your Config.cs or in the MVC controller.

Go to your IdentityServer4 Application then inside AccountController's Logout [HttpPost] method, do the following changes:

public async Task<IActionResult> Logout(LogoutViewModel model)
{
   ...    
  //return View("LoggedOut", vm);
  return Redirect(vm.PostLogoutRedirectUri);
}

This will redirect the user back to MVC application (in your case).

There is a better way to do this: You can set these options from AccountOptions.cs as follows:

public static bool ShowLogoutPrompt = false;
public static bool AutomaticRedirectAfterSignOut = true;
heyAkhilesh
  • 639
  • 6
  • 7
  • 2
    I have the same Client configuration as @Sandeep including the PostLogoutRedirectUris but when I start the project in debug mode I can see that vm.PostLogoutRedirectUri is null. Any idea why ? – CodeEngine May 24 '17 at 13:28
  • Need more clarification. Were you trying to log out from your client while you were debugging? Because, vm.PostLogoutRedirectUri will be set when the log out request is received from any of the configured clients. – heyAkhilesh Jun 01 '17 at 17:06
  • 3
    same here vm.PostLogoutRedirectUri is null – David Nov 14 '18 at 12:40
  • I solved missing PostLogoutRedirectUri with this: https://stackoverflow.com/a/44726272/1543677 – pkExec Feb 17 '23 at 08:13
13

If anyone is using the Scaffolding (they use the Razor Page files), here is how to fix it according to the answer of Akhilesh:

In Areas\Identity\Pages\Account\Logout.cshtml:

First, add IIdentityServerInteractionService service:

    IIdentityServerInteractionService _interaction;

    public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger, IIdentityServerInteractionService _interaction)
    {
        _signInManager = signInManager;
        _logger = logger;
        this._interaction = _interaction;
    }

You may need to add support for OnGet(), logic maybe different depends on your case, in my case, Get or Post does not matter:

    public async Task<IActionResult> OnGet(string returnUrl = null)
    {
        return await this.OnPost(returnUrl);
    }

Add the LogoutId logic in OnPost:

    public async Task<IActionResult> OnPost(string returnUrl = null)
    {
        await _signInManager.SignOutAsync();
        _logger.LogInformation("User logged out.");

        var logoutId = this.Request.Query["logoutId"].ToString();

        if (returnUrl != null)
        {
            return LocalRedirect(returnUrl);
        }
        else if (!string.IsNullOrEmpty(logoutId))
        {
            var logoutContext = await this._interaction.GetLogoutContextAsync(logoutId);
            returnUrl = logoutContext.PostLogoutRedirectUri;

            if (!string.IsNullOrEmpty(returnUrl))
            {
                return this.Redirect(returnUrl);
            }
            else
            {
                return Page();
            }
        }
        else
        {
            return Page();
        }
    }
Luke Vo
  • 17,859
  • 21
  • 105
  • 181
  • 1
    That's the correct response as far as the Scaffolding scenario is concerned. Thanks for sharing. I was pulling my hair trying to figure out why the post_logout_redirect_uri / returnUrl was not being passed to my Logout action. – Petar Ivanov Feb 19 '19 at 11:03
  • In my case the Request.Query["logoutId"] returns empty even though I can see it in the request url. Can you help me out on this? – Kishan Vaishnav Jun 14 '21 at 11:49
2

No extra code is needed. You should ensure if Model.AutomaticRedirectAfterSignOut=true and signout-redirect.js exists in wwwroot/js and in LoggedOut.cshtml

@if (Model.AutomaticRedirectAfterSignOut)
    {
        <script src="~/js/signout-redirect.js"></script>
    }

makes all work (see code below)

window.addEventListener("load", function () {
    var a = document.querySelector("a.PostLogoutRedirectUri");
    if (a) {
        window.location = a.href;
    }
});

thus user is redirected to mvc from LoggedOut.cshtml

Lapenkov Vladimir
  • 3,066
  • 5
  • 26
  • 37