Reputation: 145
I'm using AWS Cognito for user authentication in .NET Core 3.1 MVC application. I'm trying to logout user but it throws an error "InvalidOperationException: Cannot redirect to the end session endpoint, the configuration may be missing or invalid. Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.SignOutAsync(AuthenticationProperties properties) Microsoft.AspNetCore.Authentication.AuthenticationService.SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)"
What am I doing wrong?
UPDATE
Thanks to all who looked it up + @Tore Nestenius. The "logout_uri", at the end of this link, should be exactly (including "/" at the end) as it's in your UserPool > App integration > App client settings > Sign out URL(s). In my case, just https://localhost:XXXX/ --> "https://XXXX.auth.us-east-1.amazoncognito.com/logout?client_id=XXXX&logout_uri=https://localhost:XXXX/" The project in VS should run as "https://localhost:XXXX/" (right click project > Properties > Debug > App URL: https://localhost:XXXX/)
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
options.AccessDeniedPath = "/Authorization/AccessDenied")
.AddOpenIdConnect(options =>
{
options.ResponseType = "code";
options.MetadataAddress = Configuration["AWS:MetadataAddress"];
options.ClientId = Configuration["AWS:ClientId"];
options.ClientSecret = Configuration["AWS:ClientSecret"];
options.SaveTokens = true;
// Logout
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProviderForSignOut = context =>
{
var logoutUri = Configuration["AWS:LogOutFullPath"];
//logoutUri: "https://XXXX.auth.us-east-1.amazoncognito.com/logout?client_id=XXXX&logout_uri=http://localhost:XXXX/logout"
context.Response.Redirect(logoutUri);
context.HandleResponse();
return Task.CompletedTask;
}
};
HomeController/Logout
public async Task<IActionResult> Logout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); // <-- no error if used alone but it doesn't remove cookies
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); // <-- throws error
return RedirectToAction("Index");
}
Upvotes: 2
Views: 1677
Reputation: 19901
A proper logout should look like this:
public async Task DoLogout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
The issue is that you are not supposed to return anything from this action method, because calling Signout will in it self prepare a response of it own. If you now return a redirect, then you overwrite the response from SignOutAsync´.
For proper signout you should also consider making it a HTTP-Post operation, like
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Logout()
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
}
See this question for more details:
• Should login and logout action have CSRF protection?
Upvotes: 2