Returning SignOutResult produces an incorrectly formatted return URL
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the bug
I have an ASP.NET Core MVC application that has a sign out page. The sign out page returns a SignOutResult. The code is below ...
namespace RadixPortalWeb.Pages
{
[AllowAnonymous]
public class LogOutModel : PageModel
{
public IActionResult OnGet()
{
var schemes = new[]
{
OpenIdConnectDefaults.AuthenticationScheme,
CookieAuthenticationDefaults.AuthenticationScheme
};
return new SignOutResult(schemes);
}
}
}
For some reason, this works absolutely fine for me on my local development machine but after publishing to Azure it produces an incorrectly formatted return URL. The return URL that it's producing looks like the following ...
https://auth.wib.radixdata.com/connect/endsession?post_logout_redirect_uri=https%3A%2F%2Fportal.wib.radixdata.com%2Fsignout-callback-oidc&id_token_hint=eyJhbGciOiJSUzI1NiIsImtpZCI6IkQ0RjdBNEM4RDA1RDBFODc1NzUxMzlBMUVCRjY2MDE5IiwidHlwIjoiSldUIn0.eyJuYmYiOjE2NjA4ODY3OTksImV4cCI6MTY2MDg4NzA5OSwiaXNzIjoiaHR0cHM6Ly9hdXRoLndpYi5yYWRpeGRhdGEuY29tIiwiYXVkIjoicmFkaXgtcG9ydGFsIiwibm9uY2UiOiI2Mzc5NjQ4MzU5MzE4NDk4NjMuT1RreE5tSTRZemt0TURKa01DMDBZVEF5TFdJM01qZ3RPR1EwT1Rkak9EQTJZVEk0WkdKbU5qUXdNamt0T0RWbFppMDBOMlEwTFRoaFpEQXRObVJtWXpNNU1XWmhORFl6IiwiaWF0IjoxNjYwODg2Nzk5LCJhdF9oYXNoIjoiNWJIWWl0Y1hpRWRkYnNUUlpZMHM0USIsInNfaGFzaCI6IjJBeE1jUjBJXzRIS29tOTk4Y0E0NWciLCJzaWQiOiI0ODdFMkZDRjdCNzRCQUIyNzBBRkE3N0YyNkVEN0Y0RSIsInN1YiI6IjYwOTBmMDQ0LTNkNzItNDVmNi04ZWE0LTdkNmM2OTZlMjk0MCIsImF1dGhfdGltZSI6MTY2MDg4Njc5OCwiaWRwIjoibG9jYWwiLCJyb2xlIjoiU3lzQWRtaW4iLCJuYW1lIjoicmNvbGVAaWxzdGVjaC5jb20iLCJlbWFpbCI6InJjb2xlQGlsc3RlY2guY29tIiwid2liX2NsaWVudHMiOiJ7XCJDbGllbnRzXCI6W3tcIklkXCI6XCJyYWRpeC1wb3J0YWxcIixcIk5hbWVcIjpcInJhZGl4LXBvcnRhbFwiLFwiRGVzY3JpcHRpb25cIjpudWxsLFwiQWxsb3dlZENvcnNPcmlnaW5zXCI6W1wiaHR0cHM6Ly9wb3J0YWwud2liLnJhZGl4ZGF0YS5jb21cIl19LHtcIklkXCI6XCJyYWRpeC1hZG1pblwiLFwiTmFtZVwiOlwicmFkaXgtYWRtaW5cIixcIkRlc2NyaXB0aW9uXCI6bnVsbCxcIkFsbG93ZWRDb3JzT3JpZ2luc1wiOltcImh0dHBzOi8vYWRtaW4ud2liLnJhZGl4ZGF0YS5jb21cIl19LHtcIklkXCI6XCJ3aWItanMtd2liLXFhMTBcIixcIk5hbWVcIjpcIndpYi1qcy13aWItcWExMFwiLFwiRGVzY3JpcHRpb25cIjpudWxsLFwiQWxsb3dlZENvcnNPcmlnaW5zXCI6W1wiaHR0cHM6Ly93aWItcWExMC53aWIucmFkaXhkYXRhLmNvbVwiXX0se1wiSWRcIjpcIndpYi1qcy13aWItZGVtb3Byb2RcIixcIk5hbWVcIjpcIndpYi1qcy13aWItZGVtb3Byb2RcIixcIkRlc2NyaXB0aW9uXCI6bnVsbCxcIkFsbG93ZWRDb3JzT3JpZ2luc1wiOltcImh0dHBzOi8vd2liLWRlbW9wcm9kLndpYi5yYWRpeGRhdGEuY29tXCJdfSx7XCJJZFwiOlwid2liLWpzLXdpYi1kaXNuZXlcIixcIk5hbWVcIjpcIndpYi1qcy13aWItZGlzbmV5XCIsXCJEZXNjcmlwdGlvblwiOm51bGwsXCJBbGxvd2VkQ29yc09yaWdpbnNcIjpbXCJodHRwczovL3dpYi1kaXNuZXkud2liLnJhZGl4ZGF0YS5jb21cIl19LHtcIklkXCI6XCJ3aWItbW9iaWxlXCIsXCJOYW1lXCI6XCJ3aWItbW9iaWxlXCIsXCJEZXNjcmlwdGlvblwiOm51bGwsXCJBbGxvd2VkQ29yc09yaWdpbnNcIjpbXX1dfSIsIndpYl9hdXRob3JpemVkX2NsaWVudHMiOiJ3aWItbW9iaWxlLHJhZGl4LXBvcnRhbCxyYWRpeC1hZG1pbix3aWItanMtd2liLWRlbW9wcm9kLHdpYi1qcy13aWItcWE5LHdpYi1qcy13aWItZGlzbmV5IiwiYW1yIjpbInB3ZCJdfQ.R04av6iHh_RUJAVmLt_fUOsYy-X_z7oXs-GYrfx843xq9s5HsOiYaPm9VE8l0-W7jy451_F9s6GmFPmghAqKGRqcU6uV_Ps5XQqgWz9DpJFAOVrpFrXSgAB-YILOthIkqRpEPkrsaCBBc8B-wcQjfnbvtDbNau6VvXdBi5JfG0Jyrsi6DnH_jRqGj0YtL-ysfanZQ6qzLrAdxP_QD1J3oh_pyGsvgo_SVmjSDXqzR26Ia8mGMdyfRNnNXugaP-pCegQEKZJB639bXYe-8m1S6msXbNbpEP04TrQZWyM9f7Vo0p8AUnCiHZEwYPrv9y2ZLS53jY3VAo1dNe3GcLVq9w&state=CfDJ8EN1Dwev3BNEjT9NcowM-y2R0xEAw1veHhsgOL0mVe4luL3CbZIc6H1XAiQJgK-RHdYgzhBkBP75vWiReGdCF1-yL2nb9VXEBbB5VzHe0WvS5MLQvrg6XS_v85TqegpIHQk-uShmWSWY0nyNQTXt5i7Sv_KmNHONsTeXhVqnQsMYjPRraaqb2EfocNbn49n13g&x-client-SKU=ID_NETSTANDARD2_0&x-client-ver=5.5.0.0
which you can see contains a logout redirect URL that is not formatted correctly due to the query string starting with an ampersand instead of a question mark ...
post_logout_redirect_uri=https://portal.wib.radixdata.com/signout-callback-oidc&id_token_hint=eyJhbGciOiJSU ...
This is causing IdentityServer4 to blow out, I think, with an error that says ...
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
Any idea what's happening here?
Expected Behavior
I expect it to sign out and redirect as expected. This seems to happen just fine when running on my local dev machine.
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
6.0.400
Anything else?
This is failing when I deploy to Azure web app service. My auth server is an IdentityServer4 web application.
@ryancole Can you share more info about how your app is configured?
Specifically, anything in OpenIdConnectOptions that you're setting would be interesting to look at, as your full startup.cs with any secrets removed
@ryancole also have you taken a look at http://docs.identityserver.io/en/latest/topics/signout_external_providers.html in case some of this is relevant to your situation
@ryancole Can you share more info about how your app is configured?
Specifically, anything in
OpenIdConnectOptionsthat you're setting would be interesting to look at, as your full startup.cs with any secrets removed
Hi @adityamandaleeka, thank you for the reply.
Below is my code configuring the OIDC and Auth parts from inside the ConfigureServices method ...
public void ConfigureServices(IServiceCollection services)
{
// removed other services
services
.AddAuthentication(ConfigureAuthentication)
.AddCookie()
.AddOpenIdConnect(ConfigureOpenIdConnect);
}
private void ConfigureAuthentication(AuthenticationOptions options)
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}
private void ConfigureOpenIdConnect(OpenIdConnectOptions options)
{
var authority = m_configuration["RadixIdentityUrl"];
options.Authority = authority;
options.SignInScheme = "Cookies";
options.RequireHttpsMetadata = true;
options.ClientId = "radix-portal";
options.ClientSecret = "foo";
options.ResponseType = "code";
options.UsePkce = true;
options.SaveTokens = true;
options.Scope.Add("wib_clients");
options.Scope.Add("offline_access");
}
@ryancole also have you taken a look at http://docs.identityserver.io/en/latest/topics/signout_external_providers.html in case some of this is relevant to your situation
I have seen that page before yes but I'm not doing my sign out exactly like them. I'm not using any other upstream oidc providers like facebook etc. My sign out is simply what you can see in my original post. Maybe I should try this part of the code from that link though ...
var user = HttpContext.User;
if (user?.Identity.IsAuthenticated == true)
{
// delete local authentication cookie
await HttpContext.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(user.GetSubjectId(), user.GetName()));
}
I'm experiancing a similar problem using Ory Hydra as my OAuth/OIDC backend.
OpenIdConnectOptions:
options.ClientId = "Random UUID"
options.ClientSecret = "Random string"
options.Authority = "http://localhost:4444/"
CookieBuilder standardCookie = new() {
HttpOnly = true,
SecurePolicy = CookieSecurePolicy.None,
SameSite = SameSiteMode.Lax,
};
options.CorrelationCookie = standardCookie;
options.NonceCookie = standardCookie;
options.RequireHttpsMetadata = false;
options.ResponseMode = OpenIdConnectResponseMode.FormPost;
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("email");
options.Scope.Add("openid");
options.Scope.Add("profile");
options.DisableTelemetry = true;
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
AuthController:
[HttpGet("/logout", Name = "Logout")]
public IActionResult Logout() {
AuthenticationProperties props = new AuthenticationProperties() {
RedirectUri = "/",
};
return SignOut(props,
CookieAuthenticationDefaults.AuthenticationScheme,
OpenIdConnectDefaults.AuthenticationScheme
);
}
Request from ASP Core to the OAuth handler: GET http://localhost:4444/oauth2/sessions/logout?post_logout_redirect_uri=http%3A%2F%2Flocalhost%3A5016%2Fsignout-callback-oidc&state=CfDJ8FgE4VZSYU1Jlhlvqn0ibgr_YhEdMbsiprzK52WYmxCWMQ4cTb9fFP92s17IMxTOrAVc2LrdhNH2l4FYKKDLHWj7Ip1A6Scz76EDPiEf4m-HF-xY5zV8BY_0GUVNB74_BJQ4e_fSJUcgvFVLlmHlJWs
Trace logs from OpenIdConnectHandler:
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Trace: Entering Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler's HandleSignOutAsync.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Trace: Using properties.RedirectUri for redirect post authentication: '/'.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler: Information: AuthenticationScheme: OpenIdConnect signed out.
Actual eror:
Logout failed because query parameter state is set but id_token_hint is missing.
Oops:
return SignOut(props,
CookieAuthenticationDefaults.AuthenticationScheme,
OpenIdConnectDefaults.AuthenticationScheme
);
OpenIdConnectHandler, through an extension, calls something like:
IAuthenticationService auth = context.HttpContext.RequestServices.GetRequiredService<IAuthenticationService>();
AuthenticateResult result = await auth.AuthenticateAsync(context.HttpContext, context.Options.SignOutScheme);
context.ProtocolMessage.IdTokenHint = result?.Properties?.GetTokenValue(OpenIdConnectParameterNames.IdToken);
(context here is the RedirectContext passed to OnRedirectToIdentityProviderForSignOut that I've been playing with)
OpenIdConnectOptions.SignOutScheme defaults (through a short chain) to cookie auth, which I've just signed out from, so of course the code can't recover the IdToken to pass on because it was lost when the cookie auth was cleared. (Or something like that, I've been poking around the code all evening but there's a lot of auth code and it interacts in, uh, intresting ways).
Anyway. @ryancole, you're also siging out of cookie auth at the same time as OAuth, does your bug go away if you stop doing that?
Anyway. @ryancole, you're also siging out of cookie auth at the same time as OAuth, does your bug go away if you stop doing that?
I've not tried just that one one scheme, instead of both. I will give it a try and let you know what happens.
For some reason the bug only happens after I've published to Azure. It doesn't happen for me when debugging in Visual Studio locally. Both my IdentityServer4 and the ASPNET Core app are both debugged locally where it does not happen.
Ah yes good catch, signing out of cookie auth + oauth at the same time probably won't work. You can sign out of multiple cookies at once since those are just clearing cookies, but oauth signout won't mix as well.