-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
Federated logout (OpenID Connect) #836
Comments
#1024 solved this by passing the Then you can save the token in the JWT, and reuse it when logging the user out. For this I created a custom api endpoint: // /api/auth/federated-logout
import jwt from "next-auth/jwt"
import log from "utils/server-logger"
export default async function federatedLogout(req, res) {
try {
const token = await jwt.getToken({req, secret: process.env.SECRET, encryption: true })
if (!token) {
log.warn("No JWT token found when calling /federated-logout endpoint")
return res.redirect(process.env.NEXTAUTH_URL)
}
if (!token.idToken)
log.warn("Without an id_token the user won't be redirected back from the IdP after logout.")
const endsessionURL = `https://${process.env.PROVIDER_DOMAIN}/connect/endsession`
const endsessionParams = new URLSearchParams({
id_token_hint: token.idToken,
post_logout_redirect_uri: process.env.NEXTAUTH_URL,
})
return res.redirect(`${endsessionURL}?${endsessionParams}`)
} catch (error) {
log.error(error)
res.redirect(process.env.NEXTAUTH_URL)
}
} And when logging out on the client: <button onClick={() => window.location.href = "/api/auth/federated-logout"}>
Sign out
</button> |
Reopening, as this has not been fully resolved. We could try to support federated logout for most OIDC compliant providers out-of-the-box. |
Hey @balazsorban44 - thanks for opening this issue. I was looking into this as well because I was working on implementing
Basically that is the Or would it be possible to resolve this in a different way? Cheers, |
So my current solution for this is using the |
Thanks @balazsorban44 - how do you save the ID token from the I went on to implementing the above using the
|
Have a look at the |
Cheers @balazsorban44 - forgot to look in the |
Hi all, is an implication of this issue that people are not able to, say, switch from one Google account to another? I'm seeing that behavior on my site and wondering if this is the cause. |
You can always force a new user to login with their own credentials using https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest To make it work in next-auth, you could do: https://next-auth.js.org/getting-started/client#additional-params |
Thanks! The user is being prompted, but the issue I'm seeing is that next auth doesn't use the new account. E.g.
This still occurs with prompt: login or prompt: select_account |
It sounds like they are not being signed out from the first session in NextAuth.js (i.e. that the existing session cookie is not being deleted). NoteIf you are using a database and sign a user with a second OAuth account while they are already signed in it will securely link the accounts; the user information returned in the session will be whatever the email addresses associated with the User ID is (e.g. the email address associated with the first account they signed in with). If this is the case it is easy to view by looking at the User and Accounts tables, you will see the Accounts are both referenced to the same User ID. To unlink the OAuth accounts, simply delete the entry for the account in the Accounts table. NB: Build in pages to allow users to link/unlink accounts and to edit their profile settings are planned, but for now you would need to build your own interface to handle this. If you are not using a database then it will swap the two instead of linking (as linking accounts without a database doesn't make sense without a database to track which accounts are linked). |
@balazsorban44 Is it possible without |
Not really sure what you mean. the secret is used to retrieve the token with See the docs: https://next-auth.js.org/configuration/options#jwt |
Hi @balazsorban44, I'm trying this snippet, and it signs the user out from the auth provider successfully (if I go to the auth provider's panel it prompts me to lo in again, I'm using FusionAuth. But when the federated-logout endpoint redirects me back to the app, it still contains a valid session somehow (i.e the app calls |
you will need to call |
Alright thanks, but that'll mean the app would "flash" back briefly to then redirect to the login page since |
Hey, thanks for the answer. Yes that's is what we're doing on the |
are you actually redirected to the OAuth provider when calling the federated logout endpoint? and how do you invoke that? Remember to initiate the logout, you will need something like
I'm not really familiar with fusion auth, but you should be seeing some kind of a spinner (calling front, channel logout endpoints in iframes or similar) which then at the end redirects you back to your logout page on you site. If you don't hit the fusionauth endsession endpoint, then you will never be logged out from your provider |
Yes, that's exactly what I'm doing, using |
so the sign-in is automatic as well, using a If you stop it and just visit your FusionAuth account page after you initiated a logout, is the user logged in still on FusionAuth? That would indicate that the Provider wasn't able to log the user out for some reason. 🤔 |
Yes that's correct, the app is a dashboard so there's nothing to show unless the user is logged in.
Actually I didn't check that, I'll do that tomorrow and report back. |
Depending on your requirements, I would say the UX of logging out, then being redirected back to the login screen only to be redirected to FusionAuth again is a bit confusing IMO. Why not just stop at the logged-out screen, where you can present a login button for manual action for the user? |
Yeah, it's kinda confusing; we're still trying to iron out the UX side, this sounds like a good idea tho, I'll discuss it with the team! |
So reporting back on this, when the error happens, if I go to FusionAuth's login page directly the user is indeed logged out. |
I am all the more curious, how is the user logged in again on FusionAuth when they are redirected /logout -> /login -> FusionAuth login? 👀 😅 UPDATE: Re-reading this
means you don't actually get redirected back to FusionAuth, huh? 🤔 So for some reason, the The problem will be with One idea that comes to mind is using https://next-auth.js.org/getting-started/client#using-the-redirect-false-option-1 |
Yes these are my thoughts exactly, signOut({ callback: '/login' }).then(() => {
// some cleanup
}); But I just changed it to this: signOut({ redirect: false }).then(() => {
// some cleanup and enabling sign in button here
}); And added a button that calls |
I would do (if using signOut({ redirect: false, callbackUrl: "/login" }).then(({ url }) => {
router.push(url)
}); or await signOut({ redirect: false })
router.push("/login") This might be the problem, since without If the session is still "stuck" for some reason, doing |
Cool thank you very much for your help @balazsorban44! The latest changes appear to have fixed the issue. Nervetheless, we sometimes face the issue described in #1367 when calling |
make sure you have at least 3.27.3 installed, I think we fixed a related bug then! https://github.com/nextauthjs/next-auth/releases/tag/v3.27.3 |
I am using I am using Next-Auth with FusionAuth as Identity Provider. I have used the above comments to sign out like this.
But after that, even after I refresh the page, the I have to manually delete the cookies after signing out to make the login form appear again. Is there any way to fix this problem now? |
Hi @ngoc199, I had the same problem; this happens because FusionAuth uses SSO, so logging you from your Next app does not log you out from the FusionAuth SSO. You need to redirect to this endpoint to effectively log the user out from SSO. This is how I solved it:
That way you will be logged out from both the SSO and your app. To summarize: API route that builds the logout URL as per the docs I linked, redirect your user to that API route, FusionAuth redirects you back to the Hope that helped. |
@ngoc199 That's because your provider still has your session (there is nothing related to basically you have two sessions (one in your application, and another in provider's application)
when you are logging out from next-auth ( I can show example that we're using, we have OKTA as provider logout process: first you need to go on your provider and logout there, how to do it depend on your provider's api for example in okta it's
then provider redirect you to done! BR |
@yuriy-eleks I have tried this but still the session is not getting cleared after logout. Do you think if any more other settings that I need to tk cr to make it?? |
@medarma86 You have to try using @alessandrojcm solution. It works for me. |
@ngoc199 issue is with the signout url defined in okta dev configuration. I have done the following steps and it's working fine now.
|
My product users had trouble logging out to switch among their accounts. On my product, I use Auth0 in conjunction with Next Auth. My solution below is based on alessandrojcm's suggestion above. function handleSignOut() {
const clientId = process.env.NEXT_PUBLIC_AUTH_CLIENT_ID;
const signoutRedirectUrl = process.env.NEXT_PUBLIC_AUTH_SIGNOUT_REDIRECT_URL;
window.location.href = `https://auth.example.com/v2/logout?client_id=${clientId}&returnTo=${encodeURIComponent(
signoutRedirectUrl
)}`;
} This step logs me out of Auth0 IDP. Then where export default function SignoutPage() {
useEffect(() => {
setTimeout(() => {
signOut({ callbackUrl: window.location.origin });
}, 1000);
}, []);
return <Loading text="Please wait while we sign you out!" />;
} This step logs me out of the app by ending the session. It would be great to have this integrated into nextauth, but this solution works well for now. |
Hi, I have applied your suggestions and it work quite nice with federated-logout. But now I am struggling with next thing. When user is logged in, close the page and open it again then still will be logged in. This is fine when during login process user mark checkbox 'remember me'. But any idea how we can handle use-case when user should not be remembered after closing the page? @balazsorban44 or anyone? Do you have an idea how to overcome this issue? |
The session expires after the specified amount of time, if the user does not interact with the site before that. You can override this, please refer to the docs.
|
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Summary of proposed feature
Acces
id_token
injwt
callback, whenidToken: true
in a provider's option.Purpose of proposed feature
Make it possible to start a logout process from a
next
app usingnext-auth
that will log out from the Identity Provider entirely, if it is OIDC compliant.Detail about proposed feature
OpenID Connect compliant IdPs (like IdentiyServer4, which is also supported by
next-auth
) have a federated logout.To initiate such a logout process, when
signOut()
is called,next-auth
should redirect tohttps://idp.com/endsession
, and forward at least the two following query params:id_token_hint
: The originalid_token
received from the IdP at login.post_logout_redirect_uri
: A preconfigured URL in the IdP client, that the IdP should redirect to after a successful logout. This could default toNEXTAUTH_URL
, but could be overridden in a provider setting. (Note that the same url must be registered in the IdP client)Additional optional query params exist, see the relevant spec section
Obtaining the
id_token
at the initialjwt()
callback call would make it possible to preserve it in a session database, or in the jwt token itself.Potential problems
According to the JWT callback docs
jwt
callback has already many parameters, and adding a newidToken
would just make it worse. In my opinion should/could be provided as a single object to basically be able to use named params, but that would be a breaking change.Setting the
id_token
in the JWT cookie is kind of an overhead, as the cookie most possibly contains some kind of a mapping of the id_token (name, email, etc.) already. My solution for this would be to not store it in the cookie, but create an in-memory database (just a JS class with key value pairs, where keys are user ids, and each user contains a list of sessions, containing sessions'id_token
s. Hint: The id_token usually contains asid
or Session ID, and timestamps if needed). Adding such an in-memory database should not be required from most of the users though. (Although this could very well be an optional part ofnext-auth
, that could also complement RFC: Limit logins (by concurrency, location) #583 nicely, which I am already working on at work, and some day be able to share it as a PR tonext-auth
) I am open for suggestions here!There is the 4096 bytes cookie size limit in browser, and because of that every extra bytes count, if we cannot somehow divide the data into multiple cookies somehow. (I am no expert on cookies though, so I do not know hard it would be to split/merge cookies)
Describe any alternatives you've considered
I haven't considered alternatives to
next-auth
as it is generally a high quality full auth solution for Next.js apps, and since it already supportsidToken
for OIDC compliant IdPs, it would only make sense to leverage that even further.Additional context
OIDC spec: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
Relevant IDS4 documentation: https://identityserver4.readthedocs.io/en/latest/endpoints/endsession.html
id_token content: https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#payload-claims
Please indicate if you are willing and able to help implement the proposed feature.
If this is not a problem that can be solved in user land right now, I may be willing to try to implement this and open a PR for it, but before that, I need feedback on how to store the
id_token
in thejwt
callback, with minimal overhead.So just a TLDR:
If the user provides the
idToken: true
option as a Provider option, it would be nice to send it as a param to thejwt
callback as well. The rest can strictly speaking be implemented by the user for now.The text was updated successfully, but these errors were encountered: