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

Support for Session Cookies #2534

Closed
rikonor opened this issue Aug 15, 2021 · 23 comments
Closed

Support for Session Cookies #2534

rikonor opened this issue Aug 15, 2021 · 23 comments
Labels
enhancement New feature or request help-needed The maintainer needs help due to time constraint/missing knowledge stale Did not receive any activity for 60 days

Comments

@rikonor
Copy link

rikonor commented Aug 15, 2021

Description 📓

Per MDN/Cookies#define_the_lifetime_of_a_cookie:

  1. A Session Cookie will expire at the end of a session, e.g when the browser is closed. This is due to lacking an Expires field in the cookie.
  2. In contrast, a Permanent Cookie has an Expires field and will persist across sessions (assuming it has not expired yet).

To the best of my understanding, NextAuth always generates a Permanent Cookie as it always adds an Expires field to the cookie:

// Set cookie expiry date
const cookieExpires = new Date()
cookieExpires.setTime(cookieExpires.getTime() + sessionMaxAge * 1000)
cookie.set(res, cookies.sessionToken.name, newEncodedJwt, {
expires: cookieExpires.toISOString(),
...cookies.sessionToken.options,
})

Assuming a Sign-In page that allows users to uncheck Remember Me, a Session Cookie should be generated for the user instead of a Permanent Cookie. Is it possible to indicate to NextAuth that a Session Cookie should be created?

How to reproduce ☕️

N/A

Contributing 🙌🏽

Yes, I am willing to help implement this feature in a PR

@rikonor rikonor added the enhancement New feature or request label Aug 15, 2021
@balazsorban44
Copy link
Member

This has been asked before, but no interest was shown from the community and got stale/closed: #974

next-auth rotates the session expiry, meaning whenever the user visits the /api/auth/session endpoint (eg. through useSession()), the lifetime of the cookie is reset, keeping it active. If you use Provider as well (which I think you should and it will actually be required in the upcoming release), the default is to only visit that endpoint once in the lifetime of the page (eg.: manual reload).

I am wondering, what would your use case be?

Setting a relatively short session expiry through session.maxAge would get you almost there. Am I wrong?

Ref:
https://next-auth.js.org/configuration/options#session
https://next-auth.js.org/getting-started/client#client-max-age

@rikonor
Copy link
Author

rikonor commented Aug 16, 2021

Regarding the use-case, as mentioned in the stale issue as well - websites commonly provide a checkbox for "Remember Me", where if you uncheck the checkbox, after logging in you will have a Session Cookie, i.e a cookie with no Expires field.

This means that after you close the browser, the cookie is deleted. A common case where this is desirable is when logging in from a public computer.

Setting a lower maxAge is not a true solution to this as even if you set, e.g 1 Hour, it does not mean someone else can't re-open the browser after you leave and re-use your cookie.

The implementation for this is pretty simple, it just requires not setting an Expires field, but I'm not familiar enough with the codebase to propose the best way to do this.

Also, keep in mind I'm sure many folks can get by without this feature - but it does allow conforming to other common login systems, so IMO it's worth putting in.

@balazsorban44
Copy link
Member

balazsorban44 commented Aug 16, 2021

I did mention #974 (comment) in the other issue as well, even if our session cookie is deleted when closing the browser, the OAuth provider (assuming that this is our most popular flow) won't log you out most probably, leaving your accounts logged in anyway.

I will leave this open for discussion. Not against the idea, I just don't think it is that useful.

@rikonor
Copy link
Author

rikonor commented Aug 16, 2021

even if our session cookie is deleted when closing the browser, the OAuth provider won't log you out, leaving your accounts logged in anyway

Sorry, I think I missed this point. Lets assume this flow:

  1. Visit www.example.com and choose to log in with Google with "Remember Me" unchecked.
  2. I input my Google credentials.
  3. NextAuth provides me with a Session Cookie that gets deleted if I close the browser.
  4. I close and re-open the browser and visit www.example.com again.
  5. I choose to log in with Google again.
  6. ?

Are you saying that at the last step of this flow, Google would just log me in again without requiring my credentials? If that's the case, then I agree that this feature has little value.

EDIT: I think that "Remember Me" only really has value if the login method is credentials. Otherwise, as you mentioned, the OAuth provider will remember you anyway.

@balazsorban44
Copy link
Member

balazsorban44 commented Aug 16, 2021

Not even at step 6. You never logged out of your Google account, just go to Google and you are still logged in. There has to be an explicit action from the user's side to initiate a logout in my opinion. (Or let the session expire as is supposed to, but then you still have the being logged in issue). To log out of all the places, you will need to implement federated logout which I also mentioned in the other issue.

So yes, probably only the credentials provider would make sense here, and we actually advocate against using that, so I'm not sure we want to implement anything making that flow more appealing.

@rikonor
Copy link
Author

rikonor commented Aug 16, 2021

Sounds good. We are in agreement 🙂 .

@rikonor rikonor closed this as completed Aug 16, 2021
@kyle-mccarthy
Copy link

@balazsorban44 can this functionality be provided outside of a federated logout? I want to be able to provide different expire values based on the provider selected, specifically, I want one provider to use a session cookie and the others to persist the cookie after the browser session ends.

I don't think that federated logout is standard. Other sites/implementations of the OIDC client flow, provide the functionality to logout or expire session cookie without revoking the token from the IDP or performing a federated logout. Additionally, the ability to control the behavior of the cookie and/or session duration could help implement flows like adaptive or step-up authentication.

@balazsorban44 balazsorban44 reopened this Aug 24, 2021
@balazsorban44 balazsorban44 added the help-needed The maintainer needs help due to time constraint/missing knowledge label Aug 24, 2021
@kyle-mccarthy
Copy link

kyle-mccarthy commented Aug 24, 2021

@balazsorban44 I would be interested in making a PR for this issue. Do you have any opinions or preferences about the implementation?

@balazsorban44
Copy link
Member

On second thought, I'm not sure your usecase is generic enough to implement it in the core. What you could do is wrap NextAuth with the handler like so:

export default function auth(req, res) {
  // do anything here
  NextAuth(req, res, options)
}

and add your provider specific changes. (check req.query.nextauth)

@stale
Copy link

stale bot commented Oct 23, 2021

Hi there! It looks like this issue hasn't had any activity for a while. It will be closed if no further activity occurs. If you think your issue is still relevant, feel free to comment on it to keep it open. (Read more at #912) Thanks!

@stale stale bot added the stale Did not receive any activity for 60 days label Oct 23, 2021
@stale
Copy link

stale bot commented Oct 31, 2021

Hi there! It looks like this issue hasn't had any activity for a while. To keep things tidy, I am going to close this issue for now. If you think your issue is still relevant, just leave a comment and I will reopen it. (Read more at #912) Thanks!

@stale stale bot closed this as completed Oct 31, 2021
@ilijaNL
Copy link

ilijaNL commented Nov 10, 2021

Bump

I think to make an assumption that federated flow is most used so we don't add more functionality is not the correct way of thinking, this makes credentials provider also less secure since many closed system (think of bank) do not have any federated login which heavy rely on session closed mechanism.

@nilskaspersson
Copy link

I, too, want to allow users to not have persistent sessions, specifically for GDPR compliance. A "Remember me"-checkbox in a Credentials login flow would be sufficient cookie consent.

As proposed by the WP29:

Persistent login cookies which store an authentication token across browser sessions are not
exempted under CRITERION B. This is an important distinction because the user may not be
immediately aware of the fact that closing the browser will not clear their authentication
settings. They may return to the website under the assumption that they are anonymous whilst
in fact they are still logged in to the service. The commonly seen method of using a checkbox
and a simple information note such as “remember me (uses cookies)” next to the submit form
would be an appropriate means of gaining consent therefore negating the need to apply an
exemption in this case.

Source

@balazsorban44
Copy link
Member

balazsorban44 commented Dec 7, 2021

They are not persistent though. You can set any expiry/maxAge (can be as low as 1 sec 🤷‍♂️) and if the user does not interact with the site in that time frame, the cookie is removed by the browser.

In my experience, even Session cookies aren't removed by browsers like Chrome upon closing the window. I have to manually kill the process for it to work.

@nilskaspersson
Copy link

A short expiry would not work, I can't have sessions be terminated unexpectedly. Even then, a 1 second expiry is technically "persistent" in a way a Session cookie is not, and would require collecting user consent.

I believe the previously quoted user expectation from the WP29 is justification enough.

@balazsorban44
Copy link
Member

balazsorban44 commented Dec 8, 2021

Sessions won't be terminated. We have session rotation implemented, which means if the user tries to access any page within the allowed time, the session expiry is renewed.

Otherwise, the session expires and the cookie is automatically deleted.

See my comment here: #2534 (comment)

That would actually be worse, as if the Chrome process isn't killed forcefully (say the computer isn't turned off, and most users probably won't search/reach for the task manager/terminal), the session will never expire, which is much worse than a low expiry date.

If you set it to 8 hours (say a normal working day), the session is at most removed in the middle of the night, when nobody is checking the site.

In case the user actively logs out, the session is obviously terminated/removed immediately.

@PhilipHassialis
Copy link

As an aside, is it possible to have JWT authentication w/o any kind of cookies whatsoever? Is it possible for next-auth to simply act as a middleware where it will return the user to a configurable (e.g. custom 403 or a login) page and as soon as the user is authenticated, return us to a page that upon navigation from it or when using a call to a /api backend, be automatically checked and verified by next-auth, perhaps get a new JTW re-issued and so on in an as-possible transparent manner? The idea is not to have anything left on the browser, not even a cookie history.

The idea is not to use "sessions" at all but instead have every interaction with the next runtime be middleware-wise authenticated first by next-auth before the user can navigate to the protected pages, much like you would always send the JWT in the headers of an API call so that the API would know that a verified user is attempting to reach the endpoint.

@JensMou
Copy link

JensMou commented Mar 24, 2022

They are not persistent though. You can set any expiry/maxAge (can be as low as 1 sec 🤷‍♂️) and if the user does not interact with the site in that time frame, the cookie is removed by the browser.

In my experience, even Session cookies aren't removed by browsers like Chrome upon closing the window. I have to manually kill the process for it to work.

Hello,

I'm using an impersonation feature, where I need to remove the permanent cookies and sign in again, when you want to stop/start the impersonation. How can this be done without the controls of the cookies (and not removing them manually with javascript)? I only want to set the expiry (to -1 or whatever) in this case and not generally on the page. Maybe I missed something here.

@aleehedl
Copy link

aleehedl commented Jun 9, 2022

I also think this feature is important and shouldn't be very difficult to implement for someone with some knowledge of the code base. Conceptually, the implementation only requires that we have some setting (like maxAge: false) and the session expiration is never set to a Date value but instead to literal value Session. Or am I missing something?

Also, I find that this is useful not only for credentials method but also OAuth, because they often have the "remember me" option available as well.

For instance, when logging into Gitlab you have the "remember me" option also for when using Google login etc.

@MichaelWheldon
Copy link

Just +1 to all of this. This is the only critical feature of nextAuth I think is missing.

@naturom
Copy link

naturom commented Jul 13, 2022

I think its a critical feature as well maxAge: false. I implemented an OAuth (with permissions control), if the oauth no longer allow an user to login, currently user still able to login as the next auth session is not expired yet even when browser is reopen again. Setting the session cookie would be very helpful in such case.

@Crane101
Copy link

Might be possible to leverage NextJS middleware to achieve the desired result here? Something like this:

export const middleware = (request: NextRequest) => {
  const response = NextResponse.next();

  const authCookie = request.cookies.getWithOptions(
    config.nextAuthCookieName
  );

  if (authCookie.value) {

    response.cookies.set(
      config.nextAuthCookieName,
      authCookie.value,
      {
        ...authCookie.options,
        expires: undefined,
        maxAge: undefined,
        httpOnly: true,
        secure:
          config.nextAuthCookieName.startsWith('__Secure'),
      }
    );
  }

  return response;
};

This is only a rough POC, but it seems to work as expected when I tried it out.
Feels like it might be a terrible idea though 🙂

@tsmithdk
Copy link

tsmithdk commented Jun 6, 2024

We really need a fix for this...

Setting maxAge to a few seconds gets us halfway there however if you just refresh the browser you need to log in again. That is why we need an option to change the session-token cookie to a session only cookie. The workaround now with setting maxAge is troublesome because we have to request the provider more than necessary and it is not a 100% fix from a security aspect.

Please give an option to set maxAge to false or something in order to change the session-token cookie to a session only cookie.

The last suggestion with overwriting the cookie from middleware does not work. It changes the cookie to a session only initially but then back to containing an expirary date.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help-needed The maintainer needs help due to time constraint/missing knowledge stale Did not receive any activity for 60 days
Projects
None yet
Development

Successfully merging a pull request may close this issue.