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

Matthew C.
jump to solution

The Problem

When using Auth.js (formerly NextAuth.js) in a Next.js 13+ application that uses the App Router, you may encounter the following error:

Error: [next-auth]: `useSession` must be wrapped in a <SessionProvider />

You may also encounter this related error:

Error: React Context is unavailable in Server Components

The Solution

The SessionProvider uses React Context to share the session object between components. Because it relies on React Context, it must be used in a client component. The useSession hook can only access the session when a SessionProvider exists as an ancestor in the component tree.

The React Context is unavailable in Server Components error occurs when you try to use SessionProvider directly in a server component.

To fix both errors, create a dedicated client component that wraps children in SessionProvider, then use that wrapper in your root layout.

If you are using Auth.js v5, create a client component wrapper:

// components/SessionProviderWrapper.tsx
"use client";

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

export default function SessionProviderWrapper({
  children,
}: {
  children: React.ReactNode;
}) {
  return <SessionProvider>{children}</SessionProvider>;
}

Then use it in your root layout:

// app/layout.tsx
import SessionProviderWrapper from "@/components/SessionProviderWrapper";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <SessionProviderWrapper>
          <main>{children}</main>
        </SessionProviderWrapper>
      </body>
    </html>
  );
}

In Auth.js v5, SessionProvider automatically fetches the session, so you do not need to pass a session prop. For server components, use the auth() function directly instead of useSession:

// A server component
import { auth } from "@/auth";

export default async function ServerPage() {
  const session = await auth();

  if (!session) {
    return <p>Not authenticated</p>;
  }

  return <p>Welcome, {session.user?.name}</p>;
}

NextAuth.js v4

If you are still using NextAuth.js v4, you need to pass the session from getServerSession into the provider:

// components/SessionProviderWrapper.tsx
"use client";

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

export default function SessionProviderWrapper({
  children,
  session,
}: {
  children: React.ReactNode;
  session: Session | null;
}) {
  return <SessionProvider session={session}>{children}</SessionProvider>;
}
// app/layout.tsx
import { getServerSession } from "next-auth";
import SessionProviderWrapper from "@/components/SessionProviderWrapper";

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

  return (
    <html lang="en">
      <body>
        <SessionProviderWrapper session={session}>
          <main>{children}</main>
        </SessionProviderWrapper>
      </body>
    </html>
  );
}

If you are using the App Router with v4, prefer using getServerSession in server components instead of wrapping everything in SessionProvider, as it is unnecessary in most cases.

The "use client" directive at the top of the wrapper file marks it as a client component. The SessionProvider must be in a separate client component file from the layout, because the layout is a server component by default.

Considered "not bad" by 4 million developers and more than 150,000 organizations worldwide, Sentry provides code-level observability to many of the world's best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.

Sentry