Search code examples
next.jsnext-auth

Glitch with NextAuth session NextJS 13


I implemented NextAuth in my NextJS 13 app, but when I reload the page, and session hasn't been fetched yet, the data returns as undefined first and then after a few attempts the actual data(session) is getting returned. As result, I see the glitch on UI: Not signed in/ Signed in as ...

export default function RootLayout({ children, session }) {
  return (
    <html>
      <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      </head>
      <body>
        <SessionProvider session={session}>
            <Header />
            {children}
        </SessionProvider>
      </body>
    </html>
  )
}

Auth page:

import { useSession, signIn, signOut } from "next-auth/react"

export default function Component() {
  const { data: session } = useSession()
  if(session) {
    return <>
      Signed in as {session.user.email} <br/>
      <button onClick={() => signOut()}>Sign out</button>
    </>
  }
  return <>
    Not signed in <br/>
    <button onClick={() => signIn()}>Sign in</button>
  </>
}

Solution

  • As data is not avaialble, session will be undefined. so you need to use the status and see whether data is fetched or not. useSession() hook returns the status for you.

    If you want to have a seamless experience in a client-side implementation. you can do as below.

    import { useSession, signIn, signOut } from "next-auth/react"
    
    export default function Component() {
      const { data: session, status } = useSession()
      
      // Note: This is not mandatory. Use only if you want to show some kind of loading until you get the data
      if (status === "loading") {
        return <p>Loading...</p>
      }
    
      if (status === "unauthenticated") {
       return <>
        Not signed in <br/>
          <button onClick={() => signIn()}>Sign in</button>
        </>
      }
    
      return <>
          Signed in as {session.user.email} <br/>
          <button onClick={() => signOut()}>Sign out</button>
       </>
      
    }
    

    if you need to implement this on the server-side, the approach will be this.

    import { getServerSession } from "next-auth/next"
    import { useSession, signIn, signOut } from "next-auth/react"
    import { authOptions } from "./api/auth/[...nextauth]"
    
    
    export default function Component() {
      const { data: session } = useSession()
    
      if (typeof window === "undefined") return null
      
      if(session) {
        return <>
          Signed in as {session.user.email} <br/>
          <button onClick={() => signOut()}>Sign out</button>
        </>
      }
      
      return <>
        Not signed in <br/>
        <button onClick={() => signIn()}>Sign in</button>
      </>
      
    }
    
    export async function getServerSideProps(context) {
      return {
        props: {
          session: await getServerSession(
            context.req,
            context.res,
            authOptions
          ),
        },
      }
    }