Closed M-Pedrami closed 7 months ago
@M-Pedrami thanks for checking it out! I noticed this too and am working on it myself as we speak :pray:
I'll update you here once I find a solution
Let me know if your solution also works for the bun
runtime.
@M-Pedrami this issue seems to be solved for this project in prod. However, I think there might be an issue with Next.js still.
I'm using next@14.3.0-canary
in main
right now, and it works in prod, but it still has this error in local dev.
What seems to be happening is the following, when I first click the "Sign in" button, it takes me to /auth/signin
(the default signin page route) but renders the app/auth/login/page.tsx
content (from my custom signin page), as it should. So its showing the wrong route initially.
Then, when entering the correct PW and clicking "signin with credentials" there, it responds with the "MissingCSRF" redirect error.
However, if I manually reload the page while its showing /auth/signin
, it'll fix and show the /auth/login
route correctly in the URL bar then. And thennn the signin works without throwing the "MissingCSRF" error.
I went back through more next.js releases, and the first one to exhibit this weird path behaviour was 14.2.0-canary.48
. So anything before that, like -canary.48
or the latest 14.1.3
works both locally and in prod as expected.
Hi ndom91,
I saw the same behavior that you describe with your project and with my own project.
Just a minor thing that I saw is that initially when pressing the Sign In button, the route that is executed is "/api/auth/signin" instead of "/auth/signin", nothing that adds to the discussion xD.
I wonder if somehow this unexpected route and render management just makes a desynchronization of what CSFR token the server expects and what the OAuth provider is giving back.
I will try rolling back to the versions suggested to avoid this issue, thanks for the info!.
It works!, rolling back to 14.1.3 makes it work.
This is still not working for me in NextJS 14.2.3
Instead of using default signIn
method that does the redirect to /api/auth/
original endpoint. I do my own link
// server action to get from `next/headers` the origin
import { SIGNIN_URL } from '$/auth'
import { headers } from 'next/headers'
import { redirect } from 'next/navigation'
export async function signinLink({ redirectTo }: { redirectTo?: string }) {
const origin = headers().get('origin')
const callbackUrl = redirectTo ? redirectTo : origin ?? '/'
redirect(`${SIGNIN_URL}?callbackUrl=${callbackUrl}`)
}
And then I have a custom component that use that header
import { signinLink } from '$/auth'
function SigninLink({ redirectTo }: { redirectTo?: string }) {
return (
<form
action={async (formData) => {
'use server'
const redirectTo = formData.get('redirectTo')?.toString()
await signinLink({ redirectTo })
}}
>
<input type='hidden' name='redirectTo' value={redirectTo} />
<button type='submit'>Sign In</button>
</form>
)
}
Lastly I use that component. Note that use can pass a custom redirectTo
// My home apps/page.tsx
export default function Home() {
return <SigninLink redirectTo='/some/page' />
}
@andresgutgon Hola Andres!! Did you get this working? I am still stuck on this :(
Hola : ) Maybe try newer version of nextjs 15.0.0-canary.25. It's working for me now the same code
Yeah afaik this is a Next issue with 14.2.1+. Haven't had time to dig in further unfortunately.
There's a thread on the main next-auth repo as well here: https://github.com/nextauthjs/next-auth/issues/10585
The issue here is in env.ts it's setting the default config.basePath to "/api/auth" and so rather than attempting to load /auth/signin it's attempting to load /api/auth/signin, a refresh will cause it to load the proper path.
It's attempting to set the url to either of these: process.env.AUTH_URL ?? process.env.NEXTAUTH_URL
If not found it reverts to /api/auth
This is the code that creates the url, you can see it uses config.basePath, which defaults to /api/auth
const signInURL = createActionURL("signin", // @ts-expect-error
x-forwarded-protois not nullable, next.js sets it by default headers.get("x-forwarded-proto"), headers, process.env, config.basePath);
So for now to bypass I just direct users to "/auth/signin" directly as mentioned above. Setting one of the env vars above will break google. Still new to next-auth so maybe there's additional configurations needed to get it to work, but easiest solution is just to direct the user to "/auth/signin" yourself.
Guys I received the same error
[31m[auth][error][0m MissingCSRF: CSRF token was missing during an action signin. Read more at https://errors.authjs.dev#missingcsrf at t6 (/var/task/.next/server/chunks/277.js:17:66137) at iN (/var/task/.next/server/chunks/277.js:393:46096) at async iz (/var/task/.next/server/chunks/277.js:393:50436) at async /var/task/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:34666 at async eS.execute (/var/task/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:25813) at async eS.handle (/var/task/node_modules/next/dist/compiled/next-server/app-route.runtime.prod.js:6:35920) at async es (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:16:25461) at async ei.responseCache.get.routeKind (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:1026) at async r3.renderToResponseWithComponentsImpl (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:508) at async r3.renderPageComponent (/var/task/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:17:5028)
how can I fix this? My repo: https://github.com/RushilJalal/rushil-ecommerce-store
Try this @RushilJalal https://stackoverflow.com/a/78577718
Assuming this is a server component you do this:
import { cookies } from "next/headers";
export default async function UserButton() {
const session = await auth();
if (!session?.user) {
const csrfToken = cookies().get("authjs.csrf-token")?.value ?? ""
return <SignIn csrfToken={csrfToken} />;
}
//...
}
Then you change this component:
// ./components/auth-components.tsx
export function SignIn({
provider,
csrfToken
}: { provider?: string; csrfToken: string } & React.ComponentPropsWithRef<typeof Button>) {
return (
<form
action={async () => {
"use server";
await signIn(provider);
}}
>
<!-- HIDDEN input with the csrfToken -->
<input type="hidden" name="csrfToken" value={csrfToken} />
<Button {...props}>Sign In</Button>
</form>
);
}
if you have tried everything and still struggle , this is the code that worked for me ( i'am using next auth v5 beta and next V14 ) this is my custom signIn page :
"use client"
import { getProviders, signIn, getCsrfToken } from "next-auth/react"
import { useEffect, useState } from "react"
import clsx from "clsx"
export default function Page() {
const [providers, setProviders] = useState({})
const [csrfToken, setCsrfToken] = useState("")
useEffect(() => {
// get the csrf token from the provider
async function loadProviders() {
const authProviders = await getProviders()
setProviders(authProviders)
const csrf = await getCsrfToken()
setCsrfToken(csrf)
}
loadProviders()
}, [])
return (
<div className="flex flex-col lg:gap-4">
{/* Email / password login form */}
<form
className="flex flex-col bg-amber-50 p-16 rounded-lg gap-4 self-center"
method="post"
action="/api/auth/callback/credentials"
>
<input type="hidden" name="csrfToken" value={csrfToken} />
<div className="flex flex-col lg:max-w-[75%]">
<div className="flex flex-col">
<label htmlFor="email">
Email
<input className="border shadow-md" name="email" id="email" />
</label>
</div>
<div className="flex flex-col">
<label htmlFor="password">
Password
<input
className="border shadow-md"
name="password"
id="password"
type="password"
/>
</label>
</div>
</div>
<input
type="submit"
value="Login"
className="bg-red-500 cursor-pointer px-3 py-1 rounded-lg font-semibold text-white"
/>
</form>
{/* (Google, etc.) form */}
{providers &&
Object.values(providers).map((provider) => (
<div key={provider.name} className="self-center">
<button
onClick={() => signIn(provider.id, { callbackUrl: "/profil" })}
className={clsx("px-3 py-1 shadow-md", {
"bg-green-300": provider.name == "Google",
})}
>
<span>Connectez-vous avec {provider.name}</span>
</button>
</div>
))}
</div>
)
}
and this is my auth.ts file :
import NextAuth from "next-auth"
import Google from "next-auth/providers/google"
import Credentials from "next-auth/providers/credentials"
import type { Provider } from "next-auth/providers"
import { PrismaClient } from "@prisma/client"
const prisma = new PrismaClient()
const providers: Provider[] = [
// Credentials({
// credentials: { password: { label: "Password", type: "password" } },
// authorize(c) {
// if (c.password !== "password") return null
// return {
// id: "test",
// name: "Test User",
// email: "test@example.com",
// }
// },
// }),
Google({
clientId: process.env.AUTH_GOOGLE_ID,
clientSecret: process.env.AUTH_GOOGLE_SECRET,
}),
]
export const providerMap = providers
.map((provider) => {
if (typeof provider === "function") {
const providerData = provider()
return { id: providerData.id, name: providerData.name }
} else {
return { id: provider.id, name: provider.name }
}
})
.filter((provider) => provider.id !== "credentials")
export const { handlers, auth, signIn, signOut } = NextAuth({
// debug: true,
providers,
callbacks: {
async signIn({ user, account, profile, credentials }) {
console.log("Profil Google:", profile)
const existingUser = await prisma.user.findUnique({
where: { email: user.email },
})
if (!existingUser) {
console.log("Créer un nouvel utilisateur.")
await prisma.user.create({
data: {
name: user.name,
email: user.email,
image: user.image.replace("=s96-c", "=s400-c"),
},
})
}
return true
},
},
pages: {
signIn: "/signin",
signOut: "/signout",
},
})
if you have any question please let me know ;)
Originally I thought this worked, but I am deploying to Google (Firebase App Hosting), which fails even for the default (non-custom) sign in page
It of course works locally but fails in prod. I'm going to add to an existing next-auth issue, but reporting here as search brings people here.
Originally I thought this worked, but I am deploying to Google (Firebase App Hosting), which fails even for the default (non-custom) sign in page
It of course works locally but fails in prod. I'm going to add to an existing next-auth issue, but reporting here as search brings people here.
did you configured .env file ? in the hosting provider ? also verify that sessions are working and that this error is not related where you deployed your app .
Hello, First off thank you for the example. I cloned your repo and installed all the dependencies. The login page itself is loading however when I click on sign in with GitHub or with credentials nothing happens. The terminal logs out this error: missing csrf: csrf token was missing during an action sign in.
I appreciate any help.