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

feat: set session to the context on a server side if available #1084

Closed
wants to merge 78 commits into from

Conversation

lnikell
Copy link
Contributor

@lnikell lnikell commented Jan 11, 2021

What:
The problem described in the #844 issue. Currently using getServerSideProps and getSession don't set session context properly which results in having an extra call on the client-side even if we get it already on the server-side.

Why:

  • Avoiding extra network calls has a good impact on a performance
  • It prevents confusion during development when you retrieve a session on the server-side but then have again a call on the client-side

How:

The issue comes from the Provider, where context was always set by fetching the context with useSession. In the useSession however, there is a fallback to do a useSessionHook. This means even if we already have Session, we anyway set it only from the client-side.

export const Provider = ({ children, session, options }) => {
setOptions(options)
return createElement(SessionContext.Provider, { value: useSession(session) }, children)
}

The fix is simple, just set the value to the context which is an array of session + loading if we already have it on the server side.

https://github.com/lnikell/next-auth/blob/1c7be413f56ee304b129c31763053a4597f8a131/src/client/index.js#L294-L298

Before:

Screen.Recording.2021-01-11.at.12.39.49.mov

After:

Screen.Recording.2021-01-11.at.12.37.51.mov

Checklist:

  • Documentation n/a
  • Tests n/a
  • Ready to be merged

balazsorban44 and others added 30 commits December 5, 2020 11:11
Co-authored-by: Balázs Orbán <info@balazsorban.com>
Vercel archived their now packages a while back, so you can use vercel env pull to pull in the .env
This is a simple typographical error changed accesed to accessed
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-7769 reports a high-severity issue with the current version of nodemailer. This should be merged and released right away if possible.
the current routing for the Okta provider does not follow the standard
set by Okta, and as such doesn't allow for custom subdomains. this
update amends the routes to allow for customer subdomains, and also
aligns next-auth with Okta's documentation.
* chore(deps): upgrade "standard"

* style(lint): run lint fix

* fix(provider): optional chain Spotify provider profile img
* chore: use stale label, instead of wontfix

* chore: add link to issue explaining stalebot

* chore: fix typo in stalebot comment

* chore: run build GitHub Action on canary also

* chore: run build GitHub Actions on canary as well

* chore: add reproduction section to questions
* Fixed Reddit Authentication

* updated fix for build test

* updated buffer to avoid deprecation message

* Updated for passing tests
* update: deps

* fix: broken link

* fix: search upgrade change
* Include callbackUrl in newUser page

* Update src/server/routes/callback.js

Co-authored-by: Iain Collins <me@iaincollins.com>

* Update src/server/routes/callback.js

Co-authored-by: Iain Collins <me@iaincollins.com>

Co-authored-by: Iain Collins <me@iaincollins.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
* Add support for Fauna DB

* Add integration tests

Co-authored-by: Nico Domino <yo@ndo.dev>
Co-authored-by: styxlab <cws@DE01WP777.scdom.net>
Co-authored-by: Balázs Orbán <info@balazsorban.com>
Bumps [next](https://github.com/vercel/next.js) from 9.5.3 to 9.5.4.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](vercel/next.js@v9.5.3...v9.5.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
* Add Bungie provider

* Use absolute URL for images

* Correct image URL and use consistent formatting

Co-authored-by: Nico Domino <yo@ndo.dev>
* add provider: Microsoft

* documentation

* support no tenant setup

* fix code style

* chore: rename Microsoft provider to AzureADB2C

* chore: alphabetical order in providers/index

* doc: add provider to FAQ
…xtauthjs#895)

* Update Slack to v2 authorize urls, option for additional authorize params
* acessTokenGetter + documentation
Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 9.18.1 to 9.18.5.
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/9.18.5/CHANGES.md)
- [Commits](highlightjs/highlight.js@9.18.1...9.18.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Nico Domino <yo@ndo.dev>
This allows us to check if the user is signed in when using JWTs

Part of nextauthjs#625
* chore: use stale label, instead of wontfix

* chore: add link to issue explaining stalebot

* chore: fix typo in stalebot comment

* chore: run build GitHub Action on canary also

* chore: run build GitHub Actions on canary as well

* chore: add reproduction section to questions

* feat(provider): Add Azure Active Directory B2C (nextauthjs#809)

* add provider: Microsoft

* documentation

* support no tenant setup

* fix code style

* chore: rename Microsoft provider to AzureADB2C

* chore: alphabetical order in providers/index

* Revert "feat(provider): Add Azure Active Directory B2C (nextauthjs#809)" (nextauthjs#919)

This reverts commit 6e6a24a.

* chore: add myself to the contributors list 🙈

* docs: fix incorrect references in cypress docs

* chore: add additional docs clarification

Co-authored-by: Balázs Orbán <info@balazsorban.com>
Co-authored-by: Vladimir Evdokimov <evdokimov.vladimir@gmail.com>
* Display error if no [...nextauth].js found

fixes nextauthjs#647

* Log the error and describe it inside errors.md

Co-authored-by: Balázs Orbán <info@balazsorban.com>
balazsorban44 and others added 6 commits January 10, 2021 20:20
* chore(deps): add next and react to dev dependencies

* chore: move build configs to avoid crash with next dev

* chore: add next js dev app

* chore: remove .txt extension from LICENSE file

* chore: update CONTRIBUTING.md

* chore: watch css under development

* style(lint): run linter on index.css

* chore: fix some imports for dev server

* refactor: simplify client code

* chore: mention VSCode extension for linting

* docs: reword CONTRIBUTING.md

* chore: ignore linting pages and components
@vercel
Copy link

vercel bot commented Jan 11, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/nextauthjs/next-auth/aimedv6t5
✅ Preview: https://next-auth-git-fork-lnikell-canary.nextauthjs.vercel.app

@vercel vercel bot temporarily deployed to Preview January 11, 2021 11:40 Inactive
@vercel vercel bot temporarily deployed to Preview January 11, 2021 12:01 Inactive
@balazsorban44 balazsorban44 self-requested a review January 11, 2021 14:41
@balazsorban44
Copy link
Member

I really appreciate the before/after videos on your contributions, very helpful! Also, thanks for digging into this problem.

I am not sure if this is the perfect solution though, as it breaks the Rules of Hooks. (It does so already, _useSessionHook is not exactly called right either). I am wondering if we could work this around another way.

@lnikell
Copy link
Contributor Author

lnikell commented Jan 11, 2021

@balazsorban44 thanks, good point about hooks rules, I will refactor it a little bit.

@iaincollins
Copy link
Member

@lnikell This is great work, thank you! @balazsorban44 good catch consideration for Rules of Hooks

I think I tried to refactor this once but gave up because I couldn't work out how to do it "right". :-/

FWIW if we can't figure out how to do it without breaking the rules but we don't see any side effects in practice, personally I have no objection to going ahead anyway (although I agree, doing it without breaking them is the best scenario!).

@balazsorban44
Copy link
Member

I had a go at this at #943 but I wasn't satisfied, and got unsure if I broke anything so did not proceed. I might get back to it at a later point, but I would like to see if we come up with something smart on this PR.

@lnikell
Copy link
Contributor Author

lnikell commented Jan 17, 2021

@balazsorban44 @iaincollins I spent some time learning more the code that related to this issue and I think we can consider removing the "useSession" execution from the `Provider.

My assumptions:

  • Provider should only keep session data and don't make an api call and also keep a loading state.
  • Having useSession inside Provider creates an extra "magic" logic and can confuse users(such as me). I was confused the first time when I get calls to the "session" endpoint without having anywhere in my code useSession method.
  • If we remove useSession call from Provider we will have to add extra state to Provider to set the session, which we will run from useSession in order to update the context.

So as a temprorary solution we can go with what we have in this PR, and later consider refactoring of the Provider. I can try to make those changes if you confirm.

@kyds3k
Copy link

kyds3k commented Feb 10, 2021

I think this is causing me MANY problems! Is there any update on getting it into the main release? What can I do in the meantime?

@iaincollins
Copy link
Member

I think this is causing me MANY problems! Is there any update on getting it into the main release? What can I do in the meantime?

I would suspect it's not the cause of any problems you are having as it's more an optimisation.

Can you elaborate on sort of problems are you having and how do you think this would resolve them?

PS: If you haven't already, it might be best to post in Discussions about them and link back here.

@balazsorban44 balazsorban44 changed the base branch from canary to main February 10, 2021 13:35
@rozenmd
Copy link

rozenmd commented Mar 3, 2021

FWIW: I did a few Lighthouse tests to compare before/after of the workaround described here - the extra getSession request can increase speed index by up to 3.0 seconds.

Pretty worthwhile optimisation if you ask me.

@balazsorban44
Copy link
Member

balazsorban44 commented Mar 4, 2021

So I think I managed to work around this, without breaking the Rules of Hooks! Added in this commit: 231a66c

We can do the state initialization smarter. The interesting part is:

const [data, setData] = useState(context?.[0] ?? session)
const [loading, setLoading] = useState(!data)
...
useEffect(

So instead of calling the useEffect optionally, we set the state by first checking the context value.

One potential downside for this is that the useEffect has to be called on each render (notice in the commit, there is no dependency array at the end), but early bailout ensures that we still only fetch the session when it is needed, as before. If we wanted to go even further with this, we should move the listener logic inside the Provider, but that would require useSession() to always have a Provider above it for all the current features to work, which is a breaking change.

My solution at least prevents the extra fetch if you already provided a session which I think people here wanted. We could further optimize in a later release.

DISCLAIMER: My PR on this (#1428) is still a draft, and I have to discuss it first with Iain. So don't expect anything just yet. I just wanted to show my take on this.

@balazsorban44
Copy link
Member

Closing in favor of #1428. Thank you so much for your examples @lnikell, they helped a lot while evaluating this!

balazsorban44 added a commit that referenced this pull request Jun 11, 2021
**What**:

These changes ensure that we work more tightly with React that can also result in unforeseen performance boosts. In case we would decide on expanding to other libraries/frameworks, a new file per framework could be added.

**Why**:

Some performance issues (#844) could only be fixed by moving more of the client code into the `Provider`.

**How**:

Refactoring `next-auth/client`

Related: #1461, #1084, #1462

BREAKING CHANGE:
**1.** `next-auth/client` is renamed to `next-auth/react`.

**2.** In the past, we exposed most of the functions with different names for convenience. To simplify our source code, the new React specific client code exports only the following functions, listed with the necessary changes:

- `setOptions`: Not exposed anymore, use `SessionProvider` props
- `options`: Not exposed anymore, use `SessionProvider` props
- `session`: Rename to `getSession`
- `providers`: Rename to `getProviders`
- `csrfToken`: Rename to `getCsrfToken`
- `signin`: Rename to `signIn`
- `signout`: Rename to `signOut`
- `Provider`: Rename to `SessionProvider`

**3.** `Provider` changes.
- `Provider` is renamed to `SessionProvider`
- The `options` prop is now flattened as the props of `SessionProvider`.
- `clientMaxAge` has been renamed to `staleTime`.
- `keepAlive` has been renamed to `refetchInterval`.
An example of the changes:
```diff
- <Provider options={{clientMaxAge: 0, keepAlive: 0}}>{children}</Provider>
+ <SessionProvider staleTime={0} refetchInterval={0}>{children}</SessionProvider> 
```

**4.** It is now **required** to wrap the part of your application that uses `useSession` into a `SessionProvider`.

Usually, the best place for this is in your `pages/_app.jsx` file:

```jsx
import { SessionProvider } from "next-auth/react"

export default function App({
  Component,
  pageProps: { session, ...pageProps }
}) {
  return (
    // `session` comes from `getServerSideProps` or `getInitialProps`.
    // Avoids flickering/session loading on first load.
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}
```
mnphpexpert added a commit to mnphpexpert/next-auth that referenced this pull request Sep 2, 2024
**What**:

These changes ensure that we work more tightly with React that can also result in unforeseen performance boosts. In case we would decide on expanding to other libraries/frameworks, a new file per framework could be added.

**Why**:

Some performance issues (nextauthjs#844) could only be fixed by moving more of the client code into the `Provider`.

**How**:

Refactoring `next-auth/client`

Related: nextauthjs#1461, nextauthjs#1084, nextauthjs#1462

BREAKING CHANGE:
**1.** `next-auth/client` is renamed to `next-auth/react`.

**2.** In the past, we exposed most of the functions with different names for convenience. To simplify our source code, the new React specific client code exports only the following functions, listed with the necessary changes:

- `setOptions`: Not exposed anymore, use `SessionProvider` props
- `options`: Not exposed anymore, use `SessionProvider` props
- `session`: Rename to `getSession`
- `providers`: Rename to `getProviders`
- `csrfToken`: Rename to `getCsrfToken`
- `signin`: Rename to `signIn`
- `signout`: Rename to `signOut`
- `Provider`: Rename to `SessionProvider`

**3.** `Provider` changes.
- `Provider` is renamed to `SessionProvider`
- The `options` prop is now flattened as the props of `SessionProvider`.
- `clientMaxAge` has been renamed to `staleTime`.
- `keepAlive` has been renamed to `refetchInterval`.
An example of the changes:
```diff
- <Provider options={{clientMaxAge: 0, keepAlive: 0}}>{children}</Provider>
+ <SessionProvider staleTime={0} refetchInterval={0}>{children}</SessionProvider> 
```

**4.** It is now **required** to wrap the part of your application that uses `useSession` into a `SessionProvider`.

Usually, the best place for this is in your `pages/_app.jsx` file:

```jsx
import { SessionProvider } from "next-auth/react"

export default function App({
  Component,
  pageProps: { session, ...pageProps }
}) {
  return (
    // `session` comes from `getServerSideProps` or `getInitialProps`.
    // Avoids flickering/session loading on first load.
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.