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 Next.js 13 app directory #5647

Closed
mm-webx opened this issue Oct 26, 2022 · 74 comments · Fixed by #5741
Closed

Support Next.js 13 app directory #5647

mm-webx opened this issue Oct 26, 2022 · 74 comments · Fixed by #5741
Labels
enhancement New feature or request experimental

Comments

@mm-webx
Copy link

mm-webx commented Oct 26, 2022

Description 📓

Add some hook to use like that:

const session = use(getSession());

How to reproduce ☕️

.

Contributing 🙌🏽

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

@mm-webx mm-webx added enhancement New feature or request triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Oct 26, 2022
@MoltenCoffee
Copy link

Would this already work with the experimental unstable_getServerSession?

@mm-webx
Copy link
Author

mm-webx commented Oct 26, 2022 via email

@mm-webx
Copy link
Author

mm-webx commented Oct 26, 2022

import { use } from "react";
import { unstable_getServerSession } from "next-auth/next";
export default function Page(props) {
  console.log({ props }); // { props: { params: {}, searchParams: {} } }

  const session = use(unstable_getServerSession());  //TS2345: Argument of type '[]' is not assignable to parameter of type '[IncomingMessage & { cookies: Partial<{ [key: string]: string; }>; }, ServerResponse<IncomingMessage>, NextAuthOptions] | [...]'.   Type '[]' is not assignable to type '[NextApiRequest, NextApiResponse<any>, NextAuthOptions]'.     Source has 0 element(s) but target requires 3.

  return (
    <>
      <h1>Hi</h1>
    </>
  );
}

There is no access to req and response. Using getSession also not working, even with use client

@mm-webx
Copy link
Author

mm-webx commented Oct 26, 2022

According to this: vercel/next.js#41745 (reply in thread)

@balazsorban44 Hi, NextAuth.js maintainer here!

SessionProvider uses React's createContext which needs to be in a client component as described here.

So you can just mark the layout.tsx file with use client and it should work.

Useful resource: https://beta.nextjs.org/docs/rendering/server-and-client-components

Now that this is out, in the near future, we are going to look into how to provide better support for the new app, directory in NextAuth.js.

cc @ThangHuuVu

I created layout:

"use client";

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

export default function RootLayout({
  children,
  ...props
}: {
  children: React.ReactNode;
}) {
  console.log("layout", { props }); // empty
  return (
    <html>
      <head></head>
      <body>
        <SessionProvider session={props.session}>{children}</SessionProvider> // session not exists
      </body>
    </html>
  );
}

And some "ClientSide" component:

"use client";

import { useState } from "react";
import { useSession } from "next-auth/react";

export default function Counter() {
  const session = useSession();
  const [count, setCount] = useState(0);
  console.log({ session }); // empty
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

Where session is empty, how to access session configuration from use client component.

@mm-webx
Copy link
Author

mm-webx commented Oct 26, 2022

Current output is:

web:dev: error - ../node_modules/next-auth/react/index.js (108:27) @ eval
web:dev: error - TypeError: React.createContext is not a function
web:dev:     at eval (webpack-internal:///(sc_server)/../../node_modules/next-auth/react/index.js:136:28)
web:dev:     at Object.(sc_server)/../../node_modules/next-auth/react/index.js (/Users/webx/Work/uniproduction/uniproduction-erp/apps/web/.next/server/app/page.js:875:1)
web:dev:     at __webpack_require__ (/Users/webx/Work/uniproduction/uniproduction-erp/apps/web/.next/server/webpack-runtime.js:33:42)
web:dev:     at eval (webpack-internal:///(sc_server)/./app/page.tsx:10:73)
web:dev:     at Object.(sc_server)/./app/page.tsx (/Users/webx/Work/uniproduction/uniproduction-erp/apps/web/.next/server/app/page.js:842:1)
web:dev:     at __webpack_require__ (/Users/webx/Work/uniproduction/uniproduction-erp/apps/web/.next/server/webpack-runtime.js:33:42)
web:dev:     at Object.page (webpack-internal:///(sc_server)/../../node_modules/next/dist/build/webpack/loaders/next-app-loader.js?name=app%2Fpage&appPaths=%2Fpage&pagePath=private-next-app-dir%2Fpage.tsx&appDir=%2FUsers%2Fwebx%2FWork%2Funiproduction%2Funiproduction-erp%2Fapps%2Fweb%2Fapp&pageExtensions=tsx&pageExtensions=ts&pageExtensions=jsx&pageExtensions=js&rootDir=%2FUsers%2Fwebx%2FWork%2Funiproduction%2Funiproduction-erp%2Fapps%2Fweb&isDev=true&tsconfigPath=tsconfig.json!:19:131)
web:dev:     at collectGenerateParams (/Users/webx/Work/uniproduction/uniproduction-erp/node_modules/next/dist/build/utils.js:710:194)
web:dev:     at Object.collectGenerateParams (/Users/webx/Work/uniproduction/uniproduction-erp/node_modules/next/dist/build/utils.js:725:12)
web:dev:     at processTicksAndRejections (node:internal/process/task_queues:96:5) {
web:dev:   type: 'TypeError',
web:dev:   page: '/'
web:dev: }

@ehsanbigzad
Copy link

The below approach worked for me

app/dashboard/layout.tsx

"use client";

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

export interface DashboardLayoutProps {
  children: React.ReactNode;
}

export default function DashboardLayout({ children }: DashboardLayoutProps) {
  return (
    <SessionProvider>
      <ProfileMenu />
      {children}
    </SessionProvider>
  );
}

app/dashboard/ProfileMenu.tsx

"use client";

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

export default function ProfileMenu() {
  const { data } = useSession();

  return (
    <div>
      <p>{data?.user?.name}</p>
      <p>{data?.user?.email}</p>
    </div>
  );
}

@ehsanbigzad
Copy link

Correction of my previous comment;

Instead of marking the layout as a client component, it's better to wrap the SessionProvider in a separate client component as recommended in Nextjs 13 documentation Importing Server Components into Client Components

app/dashboard/AuthContext.tsx

"use client";

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

export interface AuthContextProps {
  children: React.ReactNode;
}

export default function AuthContext({ children }: AuthContextProps) {
  return <SessionProvider>{children}</SessionProvider>;
}

app/dashboard/layout.tsx

import AuthContext from "./AuthContext";
import ProfileMenu from "./ProfileMenu";

export interface AccountLayoutProps {
  children: React.ReactNode;
}

export default function AccountLayout({ children }: AccountLayoutProps) {
  return (
    <AuthContext>
      <ProfileMenu />
      {children}
    </AuthContext>
  );
}

@mintuz
Copy link

mintuz commented Oct 26, 2022

@ehsanbigzad https://next-auth.js.org/tutorials/securing-pages-and-api-routes#nextjs-middleware

When you supply a session prop in _app.js, useSession won't show a loading state, as it'll already have the session available. In this way, you can provide a more seamless user experience.

I did have it rendering using use(getSession()) within the React Component but causes multiple re-renders because it uses fetch internally which Next 13 has a warning against currently: See: https://beta.nextjs.org/docs/data-fetching/fetching#example-fetch-and-use-in-client-components

@tavindev
Copy link

Correction of my previous comment;

Instead of marking the layout as a client component, it's better to wrap the SessionProvider in a separate client component as recommended in Nextjs 13 documentation Importing Server Components into Client Components

app/dashboard/AuthContext.tsx

"use client";

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

export interface AuthContextProps {
  children: React.ReactNode;
}

export default function AuthContext({ children }: AuthContextProps) {
  return <SessionProvider>{children}</SessionProvider>;
}

app/dashboard/layout.tsx

import AuthContext from "./AuthContext";
import ProfileMenu from "./ProfileMenu";

export interface AccountLayoutProps {
  children: React.ReactNode;
}

export default function AccountLayout({ children }: AccountLayoutProps) {
  return (
    <AuthContext>
      <ProfileMenu />
      {children}
    </AuthContext>
  );
}

This worked for me as well. The only thing left is to get the request/response object to get the session on the layout server component and pass it to AuthContext. I can't find a way to do so on the docs tho.

@ThangHuuVu
Copy link
Member

As @ehsanbigzad has mentioned, the above solution works as an easy migration for now. 👀

This worked for me as well. The only thing left is to get the request/response object to get the session on the layout server component and pass it to AuthContext. I can't find a way to do so on the docs tho.

As for the server components, you can try the following code:

const session = await fetch("/api/auth/session").then (r => r.json()

The API could definitely be improved, though, so it's open to suggestions!

@ThangHuuVu ThangHuuVu removed the triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. label Oct 26, 2022
@IRediTOTO
Copy link

The below approach worked for me

app/dashboard/layout.tsx

"use client";

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

export interface DashboardLayoutProps {
  children: React.ReactNode;
}

export default function DashboardLayout({ children }: DashboardLayoutProps) {
  return (
    <SessionProvider>
      <ProfileMenu />
      {children}
    </SessionProvider>
  );
}

app/dashboard/ProfileMenu.tsx

"use client";

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

export default function ProfileMenu() {
  const { data } = useSession();

  return (
    <div>
      <p>{data?.user?.name}</p>
      <p>{data?.user?.email}</p>
    </div>
  );
}

This not optimize I think

@tavindev
Copy link

tavindev commented Oct 26, 2022

As @ehsanbigzad has mentioned, the above solution works as an easy migration for now. 👀

This worked for me as well. The only thing left is to get the request/response object to get the session on the layout server component and pass it to AuthContext. I can't find a way to do so on the docs tho.

As for the server components, you can try the following code:

const session = await fetch("/api/auth/session").then (r => r.json()

The API could definitely be improved, though, so it's open to suggestions!

Already tried that, but the session object comes empty, even after I log in. Not sure if I'm missing something.

This is what I have:

import { Session } from 'next-auth';
import { headers } from 'next/headers';
import Link from 'next/link';
import React, { use } from 'react';
import AuthContext from 'src/app/AuthContext';
import '../styles/globals.css';

interface RootLayoutProps {
    children: React.ReactNode;
}

async function getSession(cookie: string): Promise<Session> {
    const response = await fetch('http://localhost:3000/api/auth/session', {
        headers: {
            cookie,
        },
    });

    const session = await response.json();

    return Object.keys(session).length > 0 ? session : null;
}

export default async function RootLayout({ children }: RootLayoutProps) {
    const session = await getSession(headers().get('cookie') ?? '');

    return (
        <div className="text-white">
            <AuthContext session={session}>{children}</AuthContext>
        </div>
    );
}

@MoltenCoffee
Copy link

Tangentially related: server components do provide access to headers and cookies (which is basically what's needed for session management), but these are read-only for now.

It seems client side (as seen above) or middleware really are the only options at the moment, until Vercel implements setting cookies (which the docs say they are working on).

@mitrosunay
Copy link

How did you handle the

pages/api/auth/[...nextauth].js

section on NEXT JS 13 as api routes are not available right now ?

@tavindev
Copy link

How did you handle the

pages/api/auth/[...nextauth].js

section on NEXT JS 13 as api routes are not available right now ?

The pages folder still works alongside the app folder.

@remoblaser
Copy link

Tried these approaches but always get

TypeError: React.createContext is not a function

@remoblaser
Copy link

Tried these approaches but always get

TypeError: React.createContext is not a function

Nevermind actually, the underlying issue came from trpc / react-query to everyone who stumbles on this as well.

@galnir
Copy link

galnir commented Oct 28, 2022

Tried these approaches but always get
TypeError: React.createContext is not a function

Nevermind actually, the underlying issue came from trpc / react-query to everyone who stumbles on this as well.

You can get trpc working with next13's app directory?

@remoblaser
Copy link

remoblaser commented Oct 28, 2022

Tried these approaches but always get
TypeError: React.createContext is not a function

Nevermind actually, the underlying issue came from trpc / react-query to everyone who stumbles on this as well.

You can get trpc working with next13's app directory?

Didn't investigate further, I guess all packages will soon'ish get their respective patches and all hacks will be obsolete anyways :)

Edit: This might help you: https://github.com/trpc/next-13

@benbagley
Copy link

benbagley commented Oct 29, 2022

Hi all,

I'm giving Next 13 a shot and have it working, however, when running my test it seems that the session isn't being wrapped.

Here's what I have.

AuthContext

'use client';

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

export interface AuthContextProps {
  children: React.ReactNode;
}

export default function AuthContext({ children }: AuthContextProps) {
  return <SessionProvider>{children}</SessionProvider>;
}

layout.tsx

import './globals.css';
import { ReactNode } from 'react';
import { headers } from 'next/headers';
import AuthContext from './AuthContext';
import { Session } from 'next-auth';

export interface RootLayoutProps {
  children: ReactNode;
}

async function getSession(cookie: string): Promise<Session> {
  const response = await fetch('http://localhost:3000/api/auth/session', {
    headers: {
      cookie
    }
  });

  const session = await response.json();

  return Object.keys(session).length > 0 ? session : null;
}

export default async function RootLayout({ children }: RootLayoutProps) {
  const session = await getSession(headers().get('cookie') ?? '');

  return (
    <html lang="en">
      <head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </head>
      <body>
        <AuthContext session={session}>{children}</AuthContext>
      </body>
    </html>
  );
}

page.tsx

'use client';

import Counter from '@/components/UserTest';
import { signIn } from 'next-auth/react';
import Image from 'next/image';
import styles from './page.module.css';

export default function Home() {
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <a
          href={`/api/auth/signin`}
          onClick={(e) => {
            e.preventDefault();
            signIn();
          }}
        >
          Sign in
        </a>

        <h1 className={styles.title}>
          Welcome to <a href="https://nextjs.org">Next.js 13!</a>
        </h1>

        <Counter />

        <p className={styles.description}>
          Get started by editing{' '}
          <code className={styles.code}>app/page.tsx</code>
        </p>

        <div className={styles.grid}>
          <a href="https://beta.nextjs.org/docs" className={styles.card}>
            <h2>Documentation &rarr;</h2>
            <p>Find in-depth information about Next.js 13</p>
          </a>

          <a
            href="https://github.com/vercel/next.js/tree/canary/examples"
            className={styles.card}
          >
            <h2>Examples &rarr;</h2>
            <p>Explore the Next.js 13 playground.</p>
          </a>

          <a
            href="https://vercel.com/templates/next.js/app-directory?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
            target="_blank"
            rel="noopener noreferrer"
            className={styles.card}
          >
            <h2>Deploy &rarr;</h2>
            <p>Deploy your Next.js site to a public URL with Vercel.</p>
          </a>
        </div>
      </main>

      <footer className={styles.footer}>
        <a
          href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by{' '}
          <span className={styles.logo}>
            <Image src="/vercel.svg" alt="Vercel Logo" width={72} height={16} />
          </span>
        </a>
      </footer>
    </div>
  );
}

userTest

'use client';

import { useSession } from 'next-auth/react';

export default function UserTest() {
  const { data } = useSession();

  return (
    <>
      {console.log(data?.user)}
      <h1>Hi {data?.user?.name}</h1>
    </>
  );
}

pages/api/[...nextauth].js

import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';

export const authOptions = {
  providers: [
    CredentialsProvider({
      name: 'Sign in',
      // generate a suitable form on the sign in page.
      credentials: {
        username: {
          label: 'Email',
          type: 'email',
          placeholder: 'hello@example.com'
        },
        password: { label: 'Password', type: 'password' }
      },
      async authorize(credentials, req) {
        // const res = await fetch('/your/endpoint', {
        //   method: 'POST',
        //   body: JSON.stringify(credentials),
        //   headers: { 'Content-Type': 'application/json' }
        // });

        // const user = await res.json();

        // If no error and we have user data, return it
        // if (res.ok && user) {
        //   return user;
        // }

        // return test user
        return { id: 1, name: 'J Smith', email: 'jsmith@example.com' };

        // Return null if user data could not be retrieved
        // return null;
      }
    })
  ],
  theme: {
    colorScheme: 'dark'
  }
};

export default NextAuth(authOptions);

When running my tests I get the following:

yarn run v1.22.19
$ jest --runInBand --silent --coverage
warn  - You have enabled experimental feature (appDir) in next.config.js.
warn  - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.
info  - Thank you for testing `appDir` please leave your feedback at https://nextjs.link/app-feedback

 FAIL  app/page.spec.tsx
  ● Index.js › that the title Welcome to Next.js! exists on the page

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

      4 |
      5 | export default function UserTest() {
    > 6 |   const { data } = useSession();
        |                              ^
      7 |
      8 |   return (
      9 |     <>

      at useSession (node_modules/next-auth/react/index.js:115:11)

Here is the test

import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react';
import Home from '@/app/page';
import '@testing-library/jest-dom';

describe('Index.js', () => {
  test('that the title Welcome to Next.js! exists on the page', () => {
    render(<Home />);

    const title = screen.getByRole('heading', {
      name: /welcome to next\.js 13!/i,
      level: 1
    });

    expect(title).toBeInTheDocument();
  });

So my question is how do I go about passing userSession to the test?

@benbagley
Copy link

Update all, here is how I'm mocking the session for tests.

import React from 'react';
import { render, screen } from '@testing-library/react';
import Home from '@/app/page';
import '@testing-library/jest-dom';
import { useSession } from 'next-auth/react';

jest.mock('next-auth/react');

describe('Index.js', () => {
  test('that the title Welcome to Next.js! exists on the page', () => {
    async () => {
      (useSession as jest.Mock).mockReturnValueOnce([false, false]);

      render(<Home />);

      const title = screen.getByRole('heading', {
        name: /welcome to next\.js 13!/i,
        level: 1
      });

      expect(title).toBeInTheDocument();
    };
  });

  test('that the sign in button is clickable', () => {
    async () => {
      const mockSession = {
        expires: new Date(Date.now() + 2 * 86400).toISOString(),
        user: { name: 'Test User', email: 'testuser@example.dev' }
      };

      (useSession as jest.Mock).mockReturnValueOnce([
        mockSession,
        'authenticated'
      ]);

      render(<Home />);

      const signIn = screen.getByRole('link', {
        name: 'Sign in'
      });

      const userName = screen.findByText('Hi J Smith');

      expect(signIn).toBeInTheDocument();
      expect(userName).toBeInTheDocument();
    };
  });
});

Could be moved into some helpers but this gets the job done for now

@Bjodol
Copy link

Bjodol commented Oct 29, 2022

If someone is in need of getting the session while server-side-rendering:

import "server-only";

import { NextAuthHandler } from "next-auth/core";
import { Session } from "next-auth";
import { headers, cookies } from "next/headers";
import { authOptions } from "../pages/api/auth/[...nextauth]";

export const getSession = async (options = authOptions) => {
  const session = await NextAuthHandler<Session | {} | string>({
    options,
    req: {
      host: headers().get("x-forwarded-host") ?? "http://localhost:3000",
      action: "session",
      method: "GET",
      cookies: Array.from(cookies().entries()).reduce(
        (acc, [key]) => ({ ...acc, [key]: cookies().get(key) }),
        {}
      ),
      headers: headers(),
    },
  });

  return session;
};

Probably contains a bug or two, but seemed to unblock me.

@MoltenCoffee
Copy link

I stumbled across a repo that implements Next Auth (along with many other stuff) in Next 13, might be used for reference: https://github.com/shadcn/taxonomy

@balazsorban44 balazsorban44 changed the title Support NextJS 13 Support Next.js 13 app directory Oct 31, 2022
@MoltenCoffee
Copy link

They broke the nextjs in a solid way if the community packages are completely wrecked.

I think it's important to keep in mind that the app dir is still in beta, and as of yet does not replace the pages dir but just provides an alternative paradigm. Give it a few months.

@Willienn
Copy link

Willienn commented Mar 9, 2023

accessToken

istill working for you? (I try use and keep getting undefined)

@alessandrojcm
Copy link
Contributor

This is officially supported now: https://next-auth.js.org/configuration/nextjs#in-app-directory

Make sure to test with next@canary and next-auth@latest. If it does not work, please open an issue with a minimal reproduction.

I am trying this approach with the Next.js i18n routing example. I am calling getServerSession on the IndexPage component but I am getting the Error: Dynamic server usage: headers error; any ideas? Using both next canary and next-auth latest. Can provide a repro if needed.

@atreya2011
Copy link

atreya2011 commented Mar 19, 2023

@alessandrojcm You need to remove generateStaticParams to resolve this problem.

#5647 (comment)

@alessandrojcm
Copy link
Contributor

@alessandrojcm You need to remove generateStaticParams to resolve this problem.

#5647 (comment)

Thanks, missed that @atreya2011

@Nfinished
Copy link

I'm experiencing this without generateStaticParams. I am however calling getServerSession in a layout, is that a problem? The layout looks like it renders properly and then a component further down in the tree fails.

@militiwari
Copy link

Please update here once a stable solution is available for app directory.

@dusanlukic404
Copy link

is there any solution now for app directory?

@lassegit
Copy link

I can place the SessionProvider in any Layout except for the RootLayout (which is of course the ideal place since session is shared across the app). When it is in the RootLayout I get this error:

error - Error: [next-auth]: `useSession` must be wrapped in a <SessionProvider />
    at Layout (./...)
null

Anybody else experiencing the same?

@edwinvelez
Copy link

Looking forward to the solution.

@aimdexter
Copy link

If we use unstable_getServerSession inside RootLayout we can't use generateStaticParams anymore.
Error: Dynamic server usage: headers

any work around ?

The workaround I am using is :

  1. I created a new client component src/providers/generateStaticParamsProvider.js :
'use client'

import { useSession } from 'next-auth/react'

function GenerateStaticParamsProvider({ children }) {
  const { data: session, status } = useSession()
  if (status === 'authenticated') {
    return <div>{children}</div>
  }
}

export default GenerateStaticParamsProvider
  1. Then inside [id]/page.js :
export default async function OfferDetails({ params }) {
  const { id } = params
  const offer = await getOffer(id)
  return (
    <GenerateStaticParamsProvider>
      <SingleOffer offer={offer} />
    </GenerateStaticParamsProvider>
  )
}

export async function generateStaticParams() {
  const offers = await getOffers()
  return offers.map((offer) => ({
    id: offer.id,
  }))
}

@tusharshuklaa
Copy link

I'm using NextAuth version 4.22.1 with Next.js version 13.4. I'm getting erro 'MISSING_NEXTAUTH_API_ROUTE_ERROR'. My auth provider is Auth0.
I've followed all of the steps required as mentioned in the guidelines. Is this a bug or am I missing something?

@dvrd
Copy link

dvrd commented May 21, 2023

I'm using NextAuth version 4.22.1 with Next.js version 13.4. I'm getting erro 'MISSING_NEXTAUTH_API_ROUTE_ERROR'. My auth provider is Auth0. I've followed all of the steps required as mentioned in the guidelines. Is this a bug or am I missing something?

Did you created the route handler inside app/api/auth/[...nextauth]/route.ts

@Gyurmatag
Copy link

Yeah, I've got the same error as @tusharshuklaa. And yes I'e got my route handler in app/api/auth/[...nextauth]/route.ts, @dvrd. What is the solution here?

@tusharshuklaa
Copy link

I'm using NextAuth version 4.22.1 with Next.js version 13.4. I'm getting erro 'MISSING_NEXTAUTH_API_ROUTE_ERROR'. My auth provider is Auth0. I've followed all of the steps required as mentioned in the guidelines. Is this a bug or am I missing something?

Did you created the route handler inside app/api/auth/[...nextauth]/route.ts

Found the issue, it was my habit of camelCasingTheFileNames. I had this path app/api/auth/[...nextAuth]/route.ts, fixed it to this app/api/auth/[...nextauth]/route.ts and it started to work.
Sorry for the trouble.

@Gyurmatag
Copy link

It is still not working for me. Here is my route:
app/api/auth/[…nextauth]/route.js
And here is what is inside of it:

import prisma from '../../../../prisma/client'
import NextAuth from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'
import { Stripe } from 'stripe'
import { STRIPE_API_VERSION } from '@/config'

export const authOptions = {
  secret: process.env.AUTH_SECRET,
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
  pages: {
    signIn: '/sign-in',
  },
  events: {
    createUser: async ({ user }) => {
      const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
        apiVersion: STRIPE_API_VERSION,
      })

      await stripe.customers
        .create({
          email: user.email,
        })
        .then(async (customer) => {
          return prisma.user.update({
            where: { id: user.id },
            data: {
              stripeCustomerId: customer.id,
            },
          })
        })
    },
  },
  callbacks: {
    async session({ session, user }) {
      session.user.id = user.id

      session.user.stripeCustomerId = user.stripeCustomerId
      session.user.stripeSubTier = user.currentSubPlan

      return session
    },
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

What could be the problem here? (still getting the same error message)

@dvrd
Copy link

dvrd commented May 22, 2023

@Gyurmatag what does your sign in page looks like? You are declaring a custom sign in

@Gyurmatag
Copy link

Yeah, here you go:

import { getProviders } from 'next-auth/react'
import SignInButton from '@/app/sign-in/SignInButton'
import { getServerSession } from 'next-auth'
import { redirect } from 'next/navigation'
import { authOptions } from '@/app/api/auth/[…nextauth]/route'

export default async function SignIn() {
  const providers = await getProviders()

  const session = await getServerSession(authOptions)
  if (session) {
    redirect('/')
  }

  return (
    <>
      {providers &&
        Object.values(providers).map((provider) => (
          <div
            key={provider.name}
            className="flex justify-center rounded-md bg-white"
          >
            <SignInButton
              providerId={provider.id}
              providerName={provider.name}
            />
          </div>
        ))}
    </>
  )
}

What could be the problem?

@Gyurmatag
Copy link

Can you please help me @dvrd or @balazsorban44?

@ahmadawais
Copy link

Ditto, using generateStaticParam() and having the Error: Dynamic server usage: headers issue when trying to use. Went the route of using client side (which is not ideal) with the provider #5647 (comment)

@internationalhouseofdonald

@MoltenCoffee Next.js has released server-actions, which allow us to gather cookies from server-side components. What does this mean for fetching session server-side in Next.js 13 using the app directory?

https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions#:~:text=to%2Dcart.js-,import%20%7B%20cookies%20%7D%20from%20%27next/headers%27,-//%20Server%20action%20defined

@grepsoft
Copy link

The below approach worked for me
app/dashboard/layout.tsx

"use client";

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

export interface DashboardLayoutProps {
  children: React.ReactNode;
}

export default function DashboardLayout({ children }: DashboardLayoutProps) {
  return (
    <SessionProvider>
      <ProfileMenu />
      {children}
    </SessionProvider>
  );
}

app/dashboard/ProfileMenu.tsx

"use client";

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

export default function ProfileMenu() {
  const { data } = useSession();

  return (
    <div>
      <p>{data?.user?.name}</p>
      <p>{data?.user?.email}</p>
    </div>
  );
}

This not optimize I think

Correction of my previous comment;

Instead of marking the layout as a client component, it's better to wrap the SessionProvider in a separate client component as recommended in Nextjs 13 documentation Importing Server Components into Client Components

app/dashboard/AuthContext.tsx

"use client";

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

export interface AuthContextProps {
  children: React.ReactNode;
}

export default function AuthContext({ children }: AuthContextProps) {
  return <SessionProvider>{children}</SessionProvider>;
}

app/dashboard/layout.tsx

import AuthContext from "./AuthContext";
import ProfileMenu from "./ProfileMenu";

export interface AccountLayoutProps {
  children: React.ReactNode;
}

export default function AccountLayout({ children }: AccountLayoutProps) {
  return (
    <AuthContext>
      <ProfileMenu />
      {children}
    </AuthContext>
  );
}

Since AuthContext uses 'use client' and wraps the layout. Will the children in layout become part of the client bundle then?
Based on Next js documentation:
"This means that by defining a "use client" in a file, all other modules imported into it, including child components, are considered part of the client bundle."
source: https://nextjs.org/docs/app/building-your-application/rendering/client-components

@RahimGuerfi
Copy link

components/session-provider.tsx

"use client";

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

export { SessionProvider };

app/layout.tsx

import { SessionProvider } from "./_components/session-provider";
import { getServerSession } from "next-auth";

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request experimental
Projects
None yet
Development

Successfully merging a pull request may close this issue.