Search code examples
asp.net-coreazure-active-directoryasp.net-core-mvcmicrosoft-identity-platformmicrosoft-identity-web

How to redirect to a specific web page after sign out from Entra ID


I've got an ASP.NET Core MVC application that implements Microsoft.Identity.Web.UI nuget package for authentication against Microsoft Entra ID (formerly Azure Active Directory). The necessary App Registration has been set up & the sign in process works great. When signing out, the redirect to Entra happens, then returns to my site at /signout-oidc?state=xxxxx. There is no such page though, so I want to redirect users to a web page within my application, but I can't get it working.

In my Razor page I have the following for the Logout link:

<a href='@Url.Action("SignOut", "Account", new { Area = "MicrosoftIdentity" })'>Logout</a>

In my Program.cs the following sets up Microsoft Identity Web:

builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration)
    .EnableTokenAcquisitionToCallDownstreamApi(builder.Configuration.GetSection("MyApi:Scopes").Get<string[]>())
    .AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
    .AddInMemoryTokenCaches();

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options => {
        options.SignedOutCallbackPath = "/signout-oidc";
        options.SignedOutRedirectUri = "/home/index";
});

After the app has been built, Authentication & Authorization is enabled:

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

In terms of the Microsoft Entra ID App Registration setup, below are the redirect URIs that have been configured:

enter image description here

Now, even with setting the SignedOutRedirectUri to my site's home page & having the URL in my Web Redirect URIs list, the redirect still ends up on https://localhost:44363/signout-oidc?state=xxx, which just shows nothing as I don't have a page like that in my project.

Some additional things I've tried are:

Setting post_logout_redirect_uri parameter

On my logout link, I added the post_logout_redirect_uri query string parameter with my home page's path.

<a href='@Url.Action("SignOut", "Account", new { Area = "MicrosoftIdentity" })?post_logout_redirect_uri=%2Fhome%2Findex'>Logout</a>

Rewriting the URL

I added the following to Program.cs after the app has been built in an attempt to rewrite & redirect to my home page.

app.UseRewriter(
    new RewriteOptions()
        .AddRewrite("/signout-oidc(.*)", "/home/index", false)
);

Adding a OnSignedOutCallbackRedirect event handler

I implemented an event handler for OnSignedOutCallbackRedirect as part of the OpenIdConnectOptions configuration to attempt to redirect the response.

builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options => {
        options.SignedOutCallbackPath = "/signout-oidc";
        options.SignedOutRedirectUri = "/home/index";
        options.Events.OnSignedOutCallbackRedirect = context => {
            context.Response.Redirect(context.Options.SignedOutRedirectUri);
            context.HandleResponse();

            return Task.CompletedTask;
        };
});

None of these additional steps had the desired effect.


Solution

  • With some more digging I found the below changes resulted in a successful redirect to a page of my choosing.

    I found that if the SignedOutCallbackPath is set to anything other than /signout-oidc, then on sign out, the user gets redirected to /Account/SignOut. This happens regardless of what SignedOutRedirectUri gets set to, since it's hardcoded into the AccountController provided as part of the Microsoft.Identity.Web.UI nuget package.

    This lead to the following OpenIdConnectOptions configuration in Program.cs

    builder.Services.Configure<OpenIdConnectOptions>(
        OpenIdConnectDefaults.AuthenticationScheme,
        options => {
            options.SignedOutCallbackPath = "/signout-callback-oidc";
            options.SignedOutRedirectUri = "/Account/SignOut";
    });
    

    Next, I implemented my own AccountController, with a route that matches the signout redirect URI /Account/Signout. In this controller action, I redirect to the page I want to display:

    public class AccountController : Controller
    {
        public new IActionResult SignOut()
        {
            base.SignOut();
    
            return RedirectToAction("Index", "Home");
        }
    }
    

    Lastly, I updated my App Registration in Entra ID, setting "Front-channel logout URL" to match that of the SignedOutCallbackPath property:

    Microsoft Entra ID App Registration configuration

    Users are now correctly redirected to the public home page of the site once they've successfully signed out.

    A special thanks to Jalpa Panchal, whose response set me on the path of providing a custom implementation for URI that the site is being redirected to.