GGG
GGG

Reputation: 145

How to logout user from .net core 3.1 application using AWS Cognito and OIDC middleware

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

Answers (1)

Tore Nestenius
Tore Nestenius

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

Related Questions