Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signout does not logout user when session is being requested simultaneously #4612

Closed
snehalbaghel opened this issue May 24, 2022 · 38 comments
Closed
Labels
triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@snehalbaghel
Copy link

snehalbaghel commented May 24, 2022

Environment

 System:
    OS: macOS 12.3.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 1.18 GB / 32.00 GB
    Shell: 5.8 - /bin/zsh
 Binaries:
    Node: 14.17.0 - ~/.nvm/versions/node/v14.17.0/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 8.5.5 - ~/.nvm/versions/node/v14.17.0/bin/npm
    Watchman: 2022.03.21.00 - /usr/local/bin/watchman
 Browsers:
    Chrome: 101.0.4951.64
    Edge: 101.0.1210.53
    Firefox: 100.0.2
    Safari: 15.4
  npmPackages:
    next: ^12.0.11-canary.4 => 12.1.6 
    next-auth: latest => 4.3.4 
    react: ^17.0.2 => 17.0.2 

Reproduction URL

https://next-auth-example.vercel.app

Describe the issue

Using signOut() with multiple tabs open I discovered that sometimes the user was not getting logged out. While the /session call initially returns an empty object subsequent calls would return the user's session again failing to log out the user. This was happening because on logout my application would redirect to a specific logout page where we check if the user is authenticated by calling /session that was authenticating the user again. This is reproducible on the official example as well if we reload one of the tabs after calling sign out from the other.

How to reproduce

I reproduced the issue with the official next-auth-example project. Steps to reproduce:

  • Open the example project in two different tabs.
  • Log in to the app.
  • Sign out of the app then immediately switch to the other tab and reload the page.

Current behavior:

The signout endpoint responds with a 200 status however the session is not cleared and the user is still logged in.

Video:

Screen.Recording.2022-05-23.at.7.52.05.PM.mov

Expected behavior

The user should be logged out or the /signout API should respond with an error code.

@snehalbaghel snehalbaghel added the triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. label May 24, 2022
@crrmacarse
Copy link
Contributor

crrmacarse commented May 25, 2022

Up with this.

This seems to only happen on our prod when multiple requests are firing at once. The signOut doesn't work as intended and only refreshes the page(without logging out the user)

@ben-walcutt
Copy link

I had a similar issue with this while using the Keycloak provider. Next auth was clearing the session on the browser side, but not on the Keycloak server itself. The fix I implemented was to await the signOut function of next auth and use a callbackUrl to a signout page I created that calls the end session endpoint of Keycloak and redirects back to the website itself.

await signOut({ callbackUrl: "/api/auth/logout", });

And then pages/api/auth/logout.ts
export default (req, res) => { const url = process.env.REDIRECT_URL; res.redirect(url); }

@crrmacarse
Copy link
Contributor

Hi @ben-walcutt ,

Not related to the issue but there is a better approach on your problem by adding it on next-auth's event(https://next-auth.js.org/configuration/events#signout)

// [...next-auth].ts
events: {
    async signOut() {
      // add here
    },
  },

It'll be called after triggering signOut

@shubham-bookdepot
Copy link

@snehalbaghel snehalbaghel Are you able to fix this issue? I am also facing the same.

@balazsorban44
Copy link
Member

balazsorban44 commented Jun 20, 2022

Next auth was clearing the session on the browser side, but not on the Keycloak server itself.

This is expected as NextAuth.js does not do federated logout currently (see  #3938), so essentially what signOut does is it is clearing the session cookie, logging the user out from the app, not your Identity Provider.

When you trigger two requests at the same time though, without some kind of a locking mechanism, the two invocations to the backend will resolve differently. I don't think we can fix this without introducing something like https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API. There is already a discussion around this in #3940

To reproduce this:

Sign out of the app then immediately switch to the other tab and reload the page.

I consider this an unrealistic situation/edge case so I'm inclined to close the issue. The recommended way to solve this would be using a currently experimental API, so I don't think we can rely on it yet, but we can revisit in the future.

@DanCymonz
Copy link

events: {
async signOut() {
// add here
},
},

can i ask add what here?

@crrmacarse
Copy link
Contributor

crrmacarse commented Nov 16, 2022

can i ask add what here?

This pertains to @ben-walcutt issue when using external authentication. You can add a network request event there that un-authenticate the third party when logout is triggered

@aman-godara
Copy link

Solution:

  1. hit GET /logout endpoint of the provider to destroy user's session
  2. do signOut() to clear session cookies, only if step 1 was successful

for more details: https://stackoverflow.com/a/75484849/12581494

@ShawnCentra
Copy link

Not sure why but on production after the provider logs out the user from their service and redirects back to our web app - the session will not clear even if signOut from NextAuth is called on the client side.

NextAuth + Azure AD Provider

         <a
            href={`https://login.microsoftonline.com/${process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID}/oauth2/v2.0/logout?post_logout_redirect_uri=${process.env.NEXT_PUBLIC_NEXTAUTH_URL}/auth/signout`}
          >
            Log out
          </a>
// pages/auth/signout.js
import { signOut } from "next-auth/react";
import { useEffect } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
export default function index() {
  const router = useRouter();
  const { data: session, status } = useSession();

  useEffect(() => {
    if (status === "authenticated") {
      signOut({ redirect: false });
    } else if (status === "unauthenticated") {
      router.push("/");
    }
  }, [ status]);

  return <div></div>;
}

@iiiok
Copy link

iiiok commented May 22, 2023

Update your next.js package, besides updating the Next-Auth package.

@sergiuturus
Copy link

events: {
async signOut() {
// add here
},
},

can i ask add what here?

events: {
        async signOut({ token }) {
            const logOutUrl = new URL(`${process.env.NEXT_PUBLIC_KEYCLOAK_API_URL}/realms/${process.env.KEYCLOAK_CLIENT_ID}/protocol/openid-connect/logout`)
            logOutUrl.searchParams.set('id_token_hint', token.idToken);
            await fetch(logOutUrl);
        },
    }

@Jonas-AND
Copy link

Not sure why but on production after the provider logs out the user from their service and redirects back to our web app - the session will not clear even if signOut from NextAuth is called on the client side.

NextAuth + Azure AD Provider

         <a
            href={`https://login.microsoftonline.com/${process.env.NEXT_PUBLIC_AZURE_AD_TENANT_ID}/oauth2/v2.0/logout?post_logout_redirect_uri=${process.env.NEXT_PUBLIC_NEXTAUTH_URL}/auth/signout`}
          >
            Log out
          </a>
// pages/auth/signout.js
import { signOut } from "next-auth/react";
import { useEffect } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/router";
export default function index() {
  const router = useRouter();
  const { data: session, status } = useSession();

  useEffect(() => {
    if (status === "authenticated") {
      signOut({ redirect: false });
    } else if (status === "unauthenticated") {
      router.push("/");
    }
  }, [ status]);

  return <div></div>;
}

I've got the same issue. Did you resolve it at the end?

@gentlementlegen
Copy link

This issue still occurs, happens to me if there are more than 3 tabs open simultaneously. The user will logout and right be logged in again, the session status going from loading to unauthenticated to authenticated.

@OlgaOchichenko
Copy link

I have the same problem: This issue still occurs, happens to me if there are more than 3 tabs open simultaneously. The user will logout and right be logged in again, the session status going from loading to unauthenticated to authenticated.

@ChristopherLyon
Copy link

Hi, this is still an issue and happening to me. Any fix? What's the lastest workaround for nextjs app router? This has been open for a long time.

@ShawnCentra
Copy link

I think its because the third party provider sign out takes some time to update the server side data after initiating the request.

The above comment of doing a POST to the end point and awaiting success status -> and then calling signOut to clear the old client data should work in theory. I'd start there if I were to try again.

@valehh
Copy link

valehh commented Dec 18, 2023

Any update on this issue? Still happening. I hit the signout URL directly and the session remains there after redirecting

import {signOut } from "next-auth/react";
import { useEffect } from "react";

export default function Signout() {

useEffect(() => {
console.log("signing out of next")
signOut({ callbackUrl: "/" })
});

return <>

Signing out
}

Using next auth 4.24.4 and next 14.0.3 with App Router

@sulaimanwebdev
Copy link

Any update on this issue? Still happening. I hit the signout URL directly and the session remains there after redirecting

import {signOut } from "next-auth/react"; import { useEffect } from "react";

export default function Signout() {

useEffect(() => { console.log("signing out of next") signOut({ callbackUrl: "/" }) });

return <>

Signing out
}
Using next auth 4.24.4 and next 14.0.3 with App Router

The issue is still here, did you found any solution?

@sulaimanwebdev
Copy link

update: When there are multiple tabs open with the same user login the logout function don't work, it only works when single tab is opened. I think this is a major issue Auth.js/Next-Auth should check it.

@aman-godara
Copy link

update: When there are multiple tabs open with the same user login the logout function don't work, it only works when single tab is opened. I think this is a major issue Auth.js/Next-Auth should check it.

that's not true.
check out: https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/react.tsx#L311
when you signOut other tabs are communicated of signOut

@mrsiclorena12
Copy link

update: When there are multiple tabs open with the same user login the logout function don't work, it only works when single tab is opened. I think this is a major issue Auth.js/Next-Auth should check it.

that's not true. check out: https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/react.tsx#L311 when you signOut other tabs are communicated of signOut

It is true.

Exact same thing that @sulaimanwebdev commented out is happening to me as well.

@sulaimanwebdev
Copy link

update: When there are multiple tabs open with the same user login the logout function don't work, it only works when single tab is opened. I think this is a major issue Auth.js/Next-Auth should check it.

that's not true. check out: https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/react.tsx#L311 when you signOut other tabs are communicated of signOut

It is true.

Exact same thing that @sulaimanwebdev commented out is happening to me as well.

It got fixed, without doing anything. I just checked it :)

@stormi99
Copy link

stormi99 commented Feb 6, 2024

I am still having this issue, signOut does not delete the session. How can I delete the session by myself?

@sulaimanwebdev
Copy link

I am still having this issue, signOut does not delete the session. How can I delete the session by myself?

Delete the cookie

@nedhaf
Copy link

nedhaf commented Feb 6, 2024

Same issue with FusionAuth here... Any ideas?

@stormi99
Copy link

stormi99 commented Feb 6, 2024 via email

@stormi99
Copy link

stormi99 commented Feb 6, 2024 via email

@sulaimanwebdev
Copy link

On the left side there is button there you can delete the cookies. Delete node_modules and re install the logout issue will be solved

@bestickley
Copy link

bestickley commented Mar 7, 2024

I've resolve this issue with the following solution:

export function SignOut() {
  const router = useRouter();
  useEffect(() => {
    async function main() {
      await signOut({ redirect: false });
      router.push("/signin");
    }
    const timeout = setTimeout(() => main(), 500);
    return () => clearTimeout(timeout);
  }, [router]);
  return <LighthouseLoading />;
}

@valehh
Copy link

valehh commented Apr 3, 2024

I've resolve this issue with the following solution:

export function SignOut() {
  const router = useRouter();
  useEffect(() => {
    async function main() {
      await signOut({ redirect: false });
      router.push("/signin");
    }
    const timeout = setTimeout(() => main(), 500);
    return () => clearTimeout(timeout);
  }, [router]);
  return <LighthouseLoading />;
}

@bestickley Do you know why introducing a delay would fix the problem? I am uncomfortable with magic. Thanks.

@bestickley
Copy link

@valehh, the issue is that the API call generated from signOut and useSession are happening at the same time which prevents signOut from properly working for whatever reason. Therefore, this fix makes signOut be called after the useSession API call happens and successfully signs out user. No magic here.

@jfaMan
Copy link

jfaMan commented May 1, 2024

I've resolve this issue with the following solution:

export function SignOut() {
  const router = useRouter();
  useEffect(() => {
    async function main() {
      await signOut({ redirect: false });
      router.push("/signin");
    }
    const timeout = setTimeout(() => main(), 500);
    return () => clearTimeout(timeout);
  }, [router]);
  return <LighthouseLoading />;
}

@bestickley Unfortunately that doesn't work for me. I thought it did at first, but after a bit more testing the problem remains. I'm using FusionAuth and similarly redirect to the login page upon signout where the session is still present.

@konami99
Copy link

This answer might be helpful too https://stackoverflow.com/a/74632804/2736408

  1. First, signs out from Identity Provider (AWS Cognito)
  2. Calls signOut when 1) succeeds

@drahdavid
Copy link

I managed to solve this by using useSession instead of getSession. I was making some logic outside SessionProvider, so i had to use getSession instead of useSession. I moved this logic under this SessionProvider to implement useSession to get the current session. This stopped the concurrency conflict, and allowed a proper signout.

@FranBeltranM
Copy link

I also managed to solve this issue like drahdavid:

/api/auth/session/route.ts

image

Then I have a client component which handle the error, user profile in this case... :

image

This works like a charm, I would like to signout in server side but seems is not possible atm...

@ericblue
Copy link

Is there a reason this issue was closed? I've spent a lot of time on this the last few days. With the latest version of Nextauth (4.24.7) and next.js (14.2.5) this is unfortunately easily reproducible on even a basic example.

I'm able to consistently reproduce this with multiple tabs open with any provider - custom or with auth0 for example.

If a single window is open, session data will be cleared just fine. However, if a second tab is open, session data does not clear. I've tried many different variations of calling signOut (by itself, various options, timeout tricks, etc). and even by manually POSTing to the /api/auth/signout endpoint. I'm also tried using useSession instead of getSession, etc. but it's still the same behavior.

And this even happens with the default, unbranded GET endpoint at /api/auth/signin.

I've not had time to dig super deep into nextauth code, and frankly trying to avoid this. But it seems like there is some race condition or the session data is being reset again somewhere and aborting the signout sequence.

What's the fix here?

@drahdavid
Copy link

@ericblue Hi Eric, are you making some session update, or some logic that constanly executes (eg. useEffect) and it's outside the SessionProvider ?

@ericblue
Copy link

Hi @drahdavid Thanks for calling this out. Coincidentally last night I did make some updates and removed the signOut call that was being used in useEffect. This does seem to be working now.

It might be worth making note of this is in the getting started section or elsewhere in the docs. Along with others in this thread, there seem to be many examples elsewhere and in other threads with folks getting tripped up on this exact thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests