Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Next.js 13 and next-auth issues with useSession and SessionProvider

I'm trying to make a login page. on my page.tsx file I get either of two errors depending on if I include "use client"; at the top of my code. If I don't have "use client"; I get this error: Error: React Context is unavailable in Server Components if I do use "use client"; I get this error: Error: [next-auth]: useSession must be wrapped in a <SessionProvider />

this is my layout.tsx file:

import Image from 'next/image'
import { SessionProvider } from "next-auth/react";
import { ReactNode } from "react";
import React from 'react';

import "./globals.css";
import Link from "next/link";

type Props = {
  children: ReactNode;
  session: any;
};

export default function Layout({ children, session }: Props) {
  return (
    <html lang="en">
      <head />
      <body>
        <div className="mx-auto">
          <div className="flex flex-row flex-wrap">
            <aside className="w-full sm:w-1/3 md:w-1/5 xl:w-1/6 border-r-2 border-[#F845C6]">
              <div className="sticky top-0 p-4 w-full">
                <ul className="flex flex-col overflow-hidden">
                  <li className="m-5 text-center">
                    <Link href="login">LOGO</Link>
                  </li>
                  <li className="m-5 text-center">
                    <Link href="/">Dashboard</Link>
                  </li>
                  <li className="m-5 text-center">
                    <Link href="tasks">Tasks</Link>
                  </li>
                  <li className="m-5 text-center">
                    <Link href="reporting">Reporting</Link>
                  </li>
                </ul>
              </div>
            </aside>

            <div className="w-full sm:w-2/3 md:w-4/5 xl:w-5/6">{children}</div>
          </div>
        </div>
      </body>
    </html>
  );
}

export function getLayout(page: any) {
  const { session } = page.props;

  return (
    <SessionProvider session={session}>
      <Layout session={session}>{page}</Layout>
    </SessionProvider>
  );
}

this is the login page.tsx file:

"use client";
import React from 'react'
import { useSession, signIn, signOut } from 'next-auth/react'
import { getLayout } from '../components/Layout'

export default function Login() {
  const { data: session } = useSession();
  console.log(session);

  if (session) {
    return (
      <div style={{ fontFamily: 'sans-serif', margin: '10px 20px' }}>
        <p>Welcome, {session.user.name}</p>
        <img src={session.user.image} alt="" style={{ borderRadius: '15px', width: '80px', margin: '10px' }} />
        <button onClick={() => signOut()}>Sign out</button>
      </div>
    );
  } else {
    return (
      <div>
        <p>Please sign in</p>
        <button onClick={() => signIn("google", { callbackUrl: '/account' })}>Sign in with Google</button>
      </div>
    );
  }
}

Login.getLayout = function getLayout(page: any) {
  return getLayout(page);
};

Im trying to move from a older project to one tht uses the app directory. I tried to add the SessionProvider code that was in the original _app.js file to the root layout but Im not having any luck

like image 1000
atomic-ag Avatar asked Nov 30 '25 21:11

atomic-ag


2 Answers

For anyone else encountering this page, and in case you never resolved the issue, The SessionProvider simply needs to be wrapped in a client component which is used in the server-rendered layout, instead of being applied in the layout directly.

make a provider file:

"use client";

import { SessionProvider } from "next-auth/react";

type Props = {
  children?: React.ReactNode;
};

export const NextAuthProvider = ({ children }: Props) => {
  return <SessionProvider>{children}</SessionProvider>;
};

and then use it in your root layout like so:

type Props = {
  children: ReactNode;
};
    
export default function RootLayout({ children }: Props) {
  ...
  return (
    ...
    <NextAuthProvider>
      ...
      {children}
      ...
    </NextAuthProvider>
    ...
  );
}

This will give you access to the session context in all client-side components across the site, which is typically what you would want.


Edit: According to the SessionProvider docs:

If you pass the session page prop to the <SessionProvider> [..] you can avoid checking the session twice on pages that support both server and client side rendering.

We can modify the above RootLayout example to include this by making it an async function and by using getServerSession, as described in this GitHub issue comment:

// providers/SessionProvider.tsx

"use client";

export { SessionProvider } from "next-auth/react";
// app/layout.tsx

import { getServerSession } from "next-auth";
import { SessionProvider } from "@/providers/SessionProvider";

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const session = await getServerSession();

  ...
  return (
    ...
    <SessionProvider session={session}>
      ...
      {children}
      ...
    </SessionProvider>
    ...
  );
}
like image 120
Joseph Boyd Avatar answered Dec 03 '25 11:12

Joseph Boyd


You can re-export your SessionProvider from a client component in 2 lines:

"use client";

export { SessionProvider } from "next-auth/react";

This works for other 3rd party components that you want to turn into client components as well.

like image 25
Florian Walther Avatar answered Dec 03 '25 10:12

Florian Walther



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!