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

Error: headers was called outside a request scope, when using Authjs v5.0.0-beta.19 and next dev --turbo #11076

Open
cogb-jclaney opened this issue Jun 5, 2024 · 47 comments
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@cogb-jclaney
Copy link

Environment

  System:
    OS: Linux 5.15 Ubuntu 22.04.4 LTS 22.04.4 LTS (Jammy Jellyfish)
    CPU: (12) x64 12th Gen Intel(R) Core(TM) i7-1265U
    Memory: 5.33 GB / 15.47 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 22.0.0 - ~/.nvm/versions/node/v22.0.0/bin/node
    npm: 10.5.1 - ~/.nvm/versions/node/v22.0.0/bin/npm
  npmPackages:
    @auth/drizzle-adapter: ^1.2.0 => 1.2.0 
    next: ^14.2.3 => 14.2.3 
    next-auth: ^5.0.0-beta.18 => 5.0.0-beta.19 
    react: ^18.3.1 => 18.3.1 

Reproduction URL

https://github.com/cogb-jclaney/authjs-issue

Describe the issue

When running a Next JS site using Authjs v5.0.0-beta.19 and next dev --turbo, I get the following error - "Error: headers was called outside a request scope", running next dev without the --turbo flag works as previous.

Authjs v5.0.0-beta.18
next dev (works)
next dev --turbo (works)

Authjs v5.0.0-beta.19
next dev (works)
next dev --turbo (causes the error)

image

How to reproduce

Running the command "npm run dev" when "--turbo" is enabled cause the application to error.
Running the command without "--turbo" works normally and both with and without work on the previous version (v5.0.0-beta.18).

Credential provider has been configured for the example, no inputs actually needed, user has been hardcoded.

Expected behavior

The session from "await auth()" should be returned.

@cogb-jclaney cogb-jclaney added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Jun 5, 2024
@Qodestackr
Copy link

Qodestackr commented Jun 5, 2024

I am getting this:
Error: Invariant: headers() expects to have requestAsyncStorage, none available.

"use client";

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

import React, { ReactNode } from "react";
import { Toaster } from "react-hot-toast";

export default function Providers({ children }: { children: ReactNode }) {
  const session = getServerSession();

  console.log('straight from providers,,', session)

  return (
    <SessionProvider session={session}>
      <Toaster position="top-center" reverseOrder={false} />
      {children}
    </SessionProvider>
  );
}

What am I doing wrong? I need this to access useSession in client components but it does not work.

EDIT: I dont know how to do this in Next14 layouts:

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

export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

@Ali-Raza764
Copy link

@Qodestackr I would like to point out that wrapping your app directly with sessionprovider doesnot work instead import it in a client component and then wrap that component around your app LIKE THIS:

  return (
    <html lang="en">
      <body className={inter.className}>
        <AuthProvider>
          <Toaster />
          {children}
        </AuthProvider>
      </body>
    </html>
  );
}

And for the component

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

export default function AuthProvider({ children }) {
  return <SessionProvider>{children}</SessionProvider>;
}

@Ali-Raza764
Copy link

First thing first why did you write "use server" on the server component By default it was server component by marking you have made it a server action that works like a post request

"use server";

import { auth } from "@/lib/auth";

export async function User() {
  const session = await auth();
  return <h1>{session?.user?.name}</h1>;
}```


@Ali-Raza764
Copy link

const session = getServerSession();
In a client marked component ? @Qodestackr

@matbrgz
Copy link

matbrgz commented Jun 10, 2024

import xior from "xior"
import { auth } from "@/auth"

const iApi = xior.create({
	baseURL: API_URL,
	headers: {
		"Content-Type": "application/json",
		"Accept": "application/json",
		"Cache-Control": "no-store",
	},
})
iApi.interceptors.request.use(
	async (config) => {
		try {
			const session = await auth()
			console.log("🚀 ~ session:", session)
			config.headers.Authorization = `Bearer ${session?.user.access_token}`
			return config
		} catch (_) {
			toast.error("Erro de Autenticação. Não foi possível obter o token de acesso. Tente novamente mais tarde.")
			return Promise.reject(_)
		}
	}
)

Same error here, in any beta version of next-auth

@cogb-jclaney
Copy link
Author

First thing first why did you write "use server" on the server component By default it was server component by marking you have made it a server action that works like a post request

Thanks, I think I just overlooked that when I was trying different things in hope, I've removed it now and still get the issue.

@bilalesi
Copy link

bilalesi commented Jun 11, 2024

I just have the same issue

"use client";

const Parent = ({component}: {component: ReactNode}) => {
   // ---- other work
   return (
     <div>
        {component}
    </div>
   )
}
const ServerComponent= ({id}: {id: string})=> {
    const session = await auth();
    return (
        // ----
    )
}

const X = () => {
    const id = "xxxx";
    return (
       <Parent
          component={<ServerComponent id={id}/>}
       />
    )
}

this cause the issue:

Uncaught (in promise) Error: `headers` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context

@matbrgz
Copy link

matbrgz commented Jun 12, 2024

I create a file get-session.tsx

"use server"
import { auth } from "@/auth"

export async function getCurrentUser() {
	const session = await auth()
	return session
}

and it finally works.

@Ali-Raza764
Copy link

Ali-Raza764 commented Jun 12, 2024

I tried cloning and running the repository but it does not seen to work even after installing all the modules.

$ npm run dev

[email protected] dev
next dev
'next' is not recognized as an internal or external command,
operable program or batch file.

@Ali-Raza764
Copy link

I have myself implemented basic authentication using authjs and mongo db along with credentials and oauth providers and also implemented basic stripe payment . Take a look at the repository Here Next-auth-toolkit

@Ali-Raza764
Copy link

Also the official documentation suggests to create the auth.js file in the root of the directory. Docs

@cogb-jclaney
Copy link
Author

Hey @Ali-Raza764 thanks, odd it doesn't work for you, works for me doing the below

git clone https://github.com/cogb-jclaney/authjs-issue.git authtest
npm i
npm run dev

My app/auth works when running 'npm run dev' (next dev)
The issue is when I try use the --turbo flag 'npm run dev' (next dev --turbo) it crashes with the error above which only happens on beta.19 worked fine on beta.18

@jellohouse
Copy link

Interesting... I'm getting the same error only when I have the --turbo flag

@Ali-Raza764
Copy link

Well then do not use turbo! ??

@jellohouse
Copy link

For now yes I removed the turbo flag... but development without it is a lot slower so it's not ideal

@sbassalian
Copy link

Any update here? Local dev sucks without using turbo.

@sbassalian
Copy link

Any update here? Local dev sucks without using turbo.

Spoke too soon lol. Using versions

    "next": "14.2.5",
    "next-auth": "5.0.0-beta.18",

and working

@tbouasli
Copy link

@sbassalian I tried using those versions but the problem remains.

@came
Copy link

came commented Aug 27, 2024

having the same problem with turbo:
Error: headers was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context

"next": "14.2.6"
"next-auth": "5.0.0-beta.20"

@wilfreud
Copy link

Any update here? Local dev sucks without using turbo.

Spoke too soon lol. Using versions

    "next": "14.2.5",
    "next-auth": "5.0.0-beta.18",

and working

worke just fine for me 👍

@tconroy
Copy link

tconroy commented Aug 31, 2024

I am getting the same but with "next-auth": "^4.24.7",

@tbouasli
Copy link

tbouasli commented Sep 1, 2024

@wilfreud That's odd, if it's working for some people and others not, I don't think it's a version problem.

@keven-bardales
Copy link

I got the same issue just random problem

@Tigatok
Copy link

Tigatok commented Sep 8, 2024

Same issue, I found migrating the pages/api routes to be app router api routes solved the problem initially. That is a lot more work, the documentation appears to say I should be able to use auth(req, res)

@Mnigos
Copy link

Mnigos commented Sep 9, 2024

Same issue

    "next": "14.2.7",
    "next-auth": "5.0.0-beta.20",

I have also tried with [email protected] and [email protected]

@tbouasli
Copy link

tbouasli commented Sep 9, 2024

@wilfreud I don't think the version is the variable here, you are probably doing something different than us for it to work, could you share a snippet of your code of how you are configuring next-auth and using it? Maybe that will reveal what's actually happening for it to work for you.

@wilfreud
Copy link

wilfreud commented Sep 9, 2024

@wilfreud I don't think the version is the variable here, you are probably doing something different than us for it to work, could you share a snippet of your code of how you are configuring next-auth and using it? Maybe that will reveal what's actually happening for it to work for you.

I actually found the solution and forgot to share it here.

Hey, I may have found the issue. It appears auth() runs on the server, so I used this trick (found somewhere on stack overflow)

"use server";

import { auth } from "./auth";

export async function getAuth() {
  return await auth();
}
  • Defining getAuth as a server action, auth() is from next-auth

Update (ref): https://stackoverflow.com/a/78501195/19987002

@bonadio
Copy link

bonadio commented Sep 9, 2024

@wilfreud I don't think the version is the variable here, you are probably doing something different than us for it to work, could you share a snippet of your code of how you are configuring next-auth and using it? Maybe that will reveal what's actually happening for it to work for you.

I actually found the solution and forgot to share it here.

Hey, I may have found the issue. It appears auth() runs on the server, so I used this trick (found somewhere on stack overflow)

"use server";

import { auth } from "./auth";

export async function getAuth() {
  return await auth();
}
  • Defining getAuth as a server action, auth() is from next-auth

Update (ref): https://stackoverflow.com/a/78501195/19987002

This does not work for me. I get headers error in "return await auth();"

@tbouasli
Copy link

@wilfreud this was mentioned before in this issue by @matbrgz, although it might work, I don't see it as an definitive fix, just a workaround, but it's better than nothing. Thanks for sharing.

I create a file get-session.tsx

"use server"
import { auth } from "@/auth"

export async function getCurrentUser() {
	const session = await auth()
	return session
}

and it finally works.

@jellohouse
Copy link

jellohouse commented Sep 12, 2024

@wilfreud I don't think the version is the variable here, you are probably doing something different than us for it to work, could you share a snippet of your code of how you are configuring next-auth and using it? Maybe that will reveal what's actually happening for it to work for you.

I actually found the solution and forgot to share it here.

Hey, I may have found the issue. It appears auth() runs on the server, so I used this trick (found somewhere on stack overflow)

"use server";

import { auth } from "./auth";

export async function getAuth() {
  return await auth();
}
  • Defining getAuth as a server action, auth() is from next-auth

Update (ref): https://stackoverflow.com/a/78501195/19987002

This solution does not work for me either...

Still getting Uncaught (in promise) Error: `headers` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context

How is there no official fix for this yet... it's been months!

@raffael-sicoob
Copy link

Eu crio um arquivo get-session.tsx

"use server"
import { auth } from "@/auth"

export async function getCurrentUser() {
	const session = await auth()
	return session
}

e finalmente funciona.

This tip worked for me

@anshul-veersa
Copy link

anshul-veersa commented Oct 6, 2024

Getting the same error on standalone build of next.js with next-auth ^5.0.0-beta.22 when running the server using .next/standalone/server.js. Weirdly it works in dev env and also when running using next start. Tried different versions but still the same issue.

Edit:
Using logs I came to know, calling auth() from the file where NextAuth() is setup, it throws this error. Basically, I have this middlewares.ts

"use server";
import NextAuth, { Session } from "next-auth";
import { VerificationToken } from "next-auth/adapters";
import { NextRequest, NextResponse } from "next/server";

import { config } from "@/config";
import { authConfig } from "./config";

const { auth: getSession } = NextAuth({
  ...authConfig,
  adapter: {
    createVerificationToken: (_: VerificationToken) => undefined,
    useVerificationToken: (_: { identifier: string; token: string }) => null,
    getUserByEmail: (_: string) => null,
  },
  trustHost: true,
});

export async function attachSession() {
  try {
    return getSession();
  } catch (_) {}
}

async function getIsUserOnboarded(session: Session) {
  const session = await getSession();
  return Boolean(session?.user.onboarded);
}

export async function authenticatedUserRedirectionRules(
  request: NextRequest,
) {
  const route = request.nextUrl.pathname;

  // Check if authenticated user is onboarded
  const isUserOnboarded = await getIsUserOnboarded();

  if (isUserOnboarded && route === "/onboarding") {
    return NextResponse.redirect(
      new URL(config.routes.default.AUTH, request.url),
    );
  } else if (!isUserOnboarded && route !== "/onboarding") {
    return NextResponse.redirect(new URL("onboarding", request.url));
  }
}

the call to getSession() in getIsUserOnboarded() throws headers was called outside a request scope. So I refactored it to utilize the already available session from the next middleware where getSession() is called the first time and passing it down through authenticatedUserRedirectionRules and it works now.

@lacymorrow
Copy link
Contributor

Eu crio um arquivo get-session.tsx

"use server"
import { auth } from "@/auth"

export async function getCurrentUser() {
	const session = await auth()
	return session
}

e finalmente funciona.

This tip worked for me

This creates a server, action and an extra request. On top of that, server actions should not be used to fetch data as they are blocking. I don't believe this is a great solution.

@wilfreud
Copy link

Eu crio um arquivo get-session.tsx

"use server"
import { auth } from "@/auth"

export async function getCurrentUser() {
	const session = await auth()
	return session
}

e finalmente funciona.

This tip worked for me

This creates a server, action and an extra request. On top of that, server actions should not be used to fetch data as they are blocking. I don't believe this is a great solution.

Honestly I was in an emergency when I wrote this garbage.
Any tips on how to improve it? I'd appreciate it

@Mnigos
Copy link

Mnigos commented Oct 23, 2024

Did anyone checked if it works with next15?

@bonadio
Copy link

bonadio commented Oct 23, 2024

I just created a new Nextjs 14.2.6 and Next Auth 5.0.0-beta.25 project and now it is working

@lacymorrow
Copy link
Contributor

The latest beta works

@JulianKingman
Copy link

Seeing this issue as well... Is this where the issue lies? https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/lib/actions.ts#L18

    "next": "^15.0.1",
    "next-auth": "5.0.0-beta.25",

@Mnigos
Copy link

Mnigos commented Nov 2, 2024

Seeing this issue as well... Is this where the issue lies? https://github.com/nextauthjs/next-auth/blob/main/packages/next-auth/src/lib/actions.ts#L18

    "next": "^15.0.1",
    "next-auth": "5.0.0-beta.25",

I was hoping that it will be resolved in next@15, since they declared that turbo passed all tests on dev mode.

@JulianKingman
Copy link

I confirmed the issue with a minimal repo: https://github.com/JulianKingman/next-auth-5-nex-15-issue

It looks like NextJS doesn't approve of next/auth being used in a function that's not a page. I suspect that it might have to do with client components not being allowed to call the header function. Because the signIn function is called from the client, and it contains a call to nextHeaders(), it's erroring out.

I'm not sure what the solution is, are there any auth.js maintainers here that can either shed some light on the correct way to handle this, or look into fixing the behavior with next 15?

@lacymorrow
Copy link
Contributor

@JulianKingman it works in the latest version:
"next-auth": "5.0.0-beta.25"

@JulianKingman
Copy link

@lacymorrow unfortunately not, I'm using 5.0.0-beta.25 and used it in the repro above as well

@JulianKingman
Copy link

JulianKingman commented Nov 7, 2024

My rather ugly workaround is to make the auth functions (signIn and signOut) server actions, and create a clear distinction from client-side components. It's pretty fiddly though, and would be great if it worked client-side as well. The above repro is very minimal, let me know if there's something I should try.

@everspader
Copy link

everspader commented Nov 19, 2024

I'm seeing this issue too but only when deploying my NextJS project on Bolt.new.
On my local development everything works fine when running with both bun and npm. Deployments on Vercel also work with bun and npm. Bolt has something different that is not working with my setup.

Versions:

    "next": "^15.0.2-canary.10",
    "next-auth": "^5.0.0-beta.25",

If anyone has any clue on why it could possibly be breaking in Bolt, I'd appreciate the help. But in any case, this is how I have my working setup on local dev if anyone wants to give it a go:

  • page.ts for /auth/signin
import { AuthForm } from "@/components/auth/auth-form";
import { login } from "@/app/actions/auth-actions";

export default function SignInPage() {
  return <AuthForm type="signin" action={login} />;
}
  • auth-action.ts
"use server";

import { signIn, signOut } from "@/auth";

export const login = async (values: z.infer<typeof SignInSchema>) => {
  //... more code

  try {
    await signIn("credentials", {
      email,
      password,
      redirectTo: DEFAULT_LOGIN_REDIRECT(existingUser.defaultWorkspaceId!),
    });
    return { success: "Logged in!" };
  } catch (error) {
    //... more code
};
  • AuthForm.tsx - here I pass the action because I reuse the form for Login/SignUp
"use client";

  //... more code

export function AuthForm({ type, action }: AuthFormProps) {
  //... more code
  function onSubmit(values: z.infer<typeof schema>) {
    setError("");
    setSuccess("");

    startTransition(() => {
      action(values).then((data) => {
        setError(data?.error);
        setSuccess(data?.success);
      });
    });
  }

  return (
       ...
        <Form {...form}>
          <form onSubmit={form.handleSubmit(onSubmit)}>
            ...
          </form>
        </Form>

        
  );
}
  • auth.ts
export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut,
} = NextAuth({
  pages: {
    signIn: "/auth/signin",
    error: "/auth/error",
  },

  //... more code

  callbacks: {
    async signIn({ user, account }) {
      // Allow OAuth without email verification
      if (account?.provider !== "credentials") return true;

      const existingUser = await getUserById(user.id!);

      // Prevent sign-in if user does not exist or email is not verified
      if (!existingUser || !existingUser?.emailVerified) return false;

      // TODO: Add any additional sign-in checks here if needed

      return true;
    },

  //... more code

});

@rozenonline
Copy link

rozenonline commented Dec 17, 2024

For me, I was binding server action for extra params in client component.

'use client';

export default function TestPage() {
  const action = testAction.bind(null, "extra param"); // for extra param to the action

  return (
    <form action={action}>
      <input type="submit" />
    </form>
  );
}
import { auth } from "@/auth";

export async function testAction(extraParam: string, data: FormData) {
  const session = await auth(); 
  console.log({ extraParam, test });
}

But this causes the error..

You can bind action in server component,
Then pass it to the client component.
The error is removed...
Hope it helps

@brycefranzen
Copy link

brycefranzen commented Dec 19, 2024

Works without issues on:

"next": "15.0.4",
"next-auth": "5.0.0-beta.25",

But fails on:

"next": "15.1.0",
"next-auth": "5.0.0-beta.25",

Looks like something in next.js 15.1.0 broke things again 😩

Used within a server component (throws error on button click):

import React from "react";

import { signIn } from "~/server/auth";

const PublicPage = async () => {
  return (
    <form
      action={async () => {
        "use server";
        await signIn("google", { redirectTo: "/dashboard" });
      }}
    >
      <button type="submit">Sign In</button>
    </form>
  );
};

export default PublicPage;

Error:

index.js:635 Uncaught Error: `headers` was called outside a request scope. Read more: https://nextjs.org/docs/messages/next-dynamic-api-wrong-context
    at getExpectedRequestStore (file:///home/bryce/www/oe5/node_modules/next/dist/server/app-render/work-unit-async-storage.external.js:48:11)
    at headers (webpack-internal:///(rsc)/./node_modules/next/dist/server/request/headers.js:67:84)
    at signIn (webpack-internal:///(rsc)/./node_modules/next-auth/lib/actions.js:16:92)
    at signIn (webpack-internal:///(rsc)/./node_modules/next-auth/index.js:148:75)
    at action (webpack-internal:///(rsc)/./src/app/(landing)/page.tsx:35:63)
    at <unknown> (file:///home/bryce/www/oe5/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:157:1030)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async handleAction (file:///home/bryce/www/oe5/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:156:21940)
    at async renderToHTMLOrFlightImpl (file:///home/bryce/www/oe5/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:161:22192)
    at async doRender (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:1565:34)
    at async responseGenerator (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:1813:28)
    at async DevServer.renderToResponseWithComponentsImpl (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:1823:28)
    at async DevServer.renderPageComponent (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:2250:24)
    at async DevServer.renderToResponseImpl (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:2288:32)
    at async DevServer.pipeImpl (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:959:25)
    at async NextNodeServer.handleCatchallRenderRequest (file:///home/bryce/www/oe5/node_modules/next/dist/server/next-server.js:281:17)
    at async DevServer.handleRequestImpl (file:///home/bryce/www/oe5/node_modules/next/dist/server/base-server.js:853:17)
    at async (file:///home/bryce/www/oe5/node_modules/next/dist/server/dev/next-dev-server.js:371:20)
    at async Span.traceAsyncFn (file:///home/bryce/www/oe5/node_modules/next/dist/trace/trace.js:153:20)
    at async DevServer.handleRequest (file:///home/bryce/www/oe5/node_modules/next/dist/server/dev/next-dev-server.js:368:24)
    at async invokeRender (file:///home/bryce/www/oe5/node_modules/next/dist/server/lib/router-server.js:230:21)
    at async handleRequest (file:///home/bryce/www/oe5/node_modules/next/dist/server/lib/router-server.js:408:24)
    at async requestHandlerImpl (file:///home/bryce/www/oe5/node_modules/next/dist/server/lib/router-server.js:432:13)
    at async Server.requestListener (file:///home/bryce/www/oe5/node_modules/next/dist/server/lib/start-server.js:146:13)

This error occurs with or without the --turbo flag. Doesn't matter.

@alxcrt
Copy link

alxcrt commented Dec 22, 2024

any updates @brycefranzen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests