Search code examples
asp.net-mvcasp.net-coreopenidopenid-connect

ASP.NET Core, route is not triggered when defined as OpenId SignedOutCallbackPath


I have this controller

    [Route("Authentication")]
    public class AuthenticationController : Controller
    {

and this action

        [HttpGet("SignOut")]
        public async Task<IActionResult> SignOut([FromQuery] string sid)
        {
            await ControllerContext.HttpContext.SignOutAsync(Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectDefaults.AuthenticationScheme);
            await ControllerContext.HttpContext.SignOutAsync(Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationDefaults.AuthenticationScheme);


            return View();

This works as expected.

But when I configure a SignedOutCallbackPath for my OpenId authentication that has the same route, it doesn't work anymore. The constructor of my controller is not called, the action is not hit and the result in the browser is a blank page (code 200) with html/head/body, but all empty, that doesn't match any template or view.

            services.AddAuthentication(options =>
            {
                options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
            })
            .AddCookie(options =>
            {
                options.Cookie.HttpOnly = true;
            })
            .AddOpenIdConnect(options =>
            {
                options.SignedOutCallbackPath = "/Authentication/SignOut";

Is the SignedOutCallbackPath not supposed to be a view of my own?


Solution

  • The callback paths in the OpenID Connect authentication scheme are internal paths that are used for the authentication flow of the OpenID Connect protocol. There are three of those:

    • CallbackPath – The path the authentication provider posts back when authenticating.
    • SignedOutCallbackPath – The path the authentication provider posts back after signing out.
    • RemoteSignOutPath – The path the authentication provider posts back after signing out remotely by a third-party application.

    As you can see from my explanation, these are all URLs that the authentication provider uses: They are part of the authentication flow and not to be directly used by your users. You also don’t need to worry about handling those things. The OpenID Connect authentication handler will automatically respond to these requests when the authentication middleware runs.

    This means that when you change a callback path to some path that is a route of one of your controller actions, then the authentication middleware will handle that request before your controller gets involved. This is by design, so that you do not need to worry about these routes as they are mostly internal.

    You just have the option to change those paths if you cannot or do not want to use the default values.

    Now, there are two possible things I can think of that you could have meant to change instead:

    • SignedOutRedirectUri: This is the URL the user gets redirected to after the sign-out process is completed. This basically allows you to send the user to some view with e.g. a message “you were successfully signed out”, to show that the sign-out is done.

      You can also set this as part of the AuthenticationProperties that you can pass to the SignOutAsync.

    • CookieAuthenticationOptions.LogoutPath: This is the URL that is configured to the actual URL that users can go to to sign out of the application. This does not really have that much of an effect though.

    Otherwise, it’s really up to you to send users to your /Authentication/SignOut URL. You can put a button into your layout that goes there for example, to offer users a sign out functionality at all times.