-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
in the middleware, the session is not extended with custom fields #9836
Comments
I too am facing this issue. The middleware's the only place I'm not having custom fields returned. Have you been able to find a fix? |
@deltasierra96 Nothing 😔 |
@SebastianNarvaez11 @deltasierra96 I also faced this issue, what seems to have worked for me was combining my NextAuth instantiations. The FixYou have called Your import NextAuth from "next-auth";
import authConfig from "@/auth.config";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth(authConfig); Your import type { NextAuthConfig } from "next-auth";
// ... Prisma Imports
export default {
providers: [...],
pages: {
signIn: "/auth/login",
error: "/auth/error",
},
session: { strategy: "jwt" },
callbacks: {
authorized({ request, auth }) {
console.log("Please Remove Me. This is a POC", auth) // <-- This should have your additional user data!
return true;
},
async session({ token, session }) {
if (token?.data?.role && session.user) {
session.user.role = token.data.role;
}
return session;
},
async jwt({ token }) {
// ... Your Prisma Code
token.data = user
return token;
},
},
} satisfies NextAuthConfig; This should resolve the issue. I have freehand typed this in GitHub so this code will probably not be perfect and will almost 100% have at least 1 error, but the idea should be there enough to hopefully help the issue. The (assumed) Root CauseIt seems the actual cause is because the instantiations are different, calling TL;DRYou need to use one configuration/NextAuth instantiation for both your providers & middleware
Just follow the full fix, its not too long... I hope that fixes your issue - If this is the problem for you, it seems the problem is NOT with next-auth. It may be worth documenting this somewhere though as its (IMO) an easy mistake to make! |
THIS ABSOLUTELY WORKS! Lets hope they either document it or fix it. |
But with |
Thanks for reporting, and thanks @ConnorC18 for explaining, that is exactly what we recommend at the moment. Some of us are working on a new doc to address this use-case, cc @ndom91 @ubbe-xyz 🙏 |
@AmphibianDev I think you can define the next-auth/apps/dev/nextjs/auth.ts Line 37 in 234a150
|
Prisma doesn't support edge runtimes yet though, that's right. In their most recent change log for Thanks for the ping though thang. Definitely something we have to be clear about in the docs 👍 |
I already did; here is my repo: https://github.com/AmphibianDev/todo-app. @ndom91, are you saying it's impossible for me to get the user custom fields I'm quite new to Next.js and next-auth, so I started with a simple ToDo App to get the hang of things. Sorry to bother, but I have one more question, if I may: If I protect a route in the |
@AmphibianDev ah okay, no so only if you're running on an edge runtime then Prisma has issues, although they can be worked around like implied by Thang and ConnorC18 detailed. "slef hosting" the Next.js app on a VPS should be fine. Make sure to use Regarding your second question the mdidleware runs in front of every request (unless you white / blacklist something in the "matchers" setting), so your server actions should be covered 👍 |
@ndom91, I did like ConnorC18 and Thang implied, but I got the error:
If I move the |
@AmphibianDev make sure you are not calling prisma in the |
Also make sure you are copying over |
@ConnorC18 Believe me, I have tried every combination of moves possible. 😓
I have removed any auth check from my app and made it easier to spin up: https://github.com/AmphibianDev/todo-app I want to make this work so bad... 😞 |
Hi everyone.
export const { handlers, auth, signIn, signOut } = NextAuth({...authConfig})
All is good until you want to add Now you should be able to use the same exported How did I resolve this?I moved the adapter and any callbacks requiring DB access into import NextAuth from 'next-auth'
import { authConfig } from './auth.config'
const auth = NextAuth(authConfig).auth
export default auth((req) => {
// Do some routing stuff here if you want
// The `req.auth` will have all the fields that you returned via the `session` callback
}) Use the above hack until the adapters support running on edge.
|
Im currently battleing this behaviour too, fighting it for 6 days now. Can you please share your code so we can see what was done in order to get this going? I have tried using prisma - only with accelerate which is paid, drizzle - "edgeFunction is not defined". |
@jainmohit2001 I don't get it, I tried following what you said, but they still don't have all the fields returned from the middleware.ts import NextAuth from "next-auth";
import authConfig from "@/auth.config";
const { auth } = NextAuth(authConfig);
export default auth((req) => {
console.log(req.auth?.user); // => only { email: 'myemail@gmail.com' }
});
export const config = {
matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
}; auth.ts import NextAuth from "next-auth";
import authConfig from "@/auth.config";
import prisma from "@/lib/prisma";
import { PrismaAdapter } from "@auth/prisma-adapter";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
callbacks: {
async session({ session, token }) {
if (token.sub && session.user) {
session.user.id = token.sub;
session.user.role = token.role;
}
return session;
},
async jwt({ token }) {
if (!token.sub) return token;
const user = await prisma.user.findUnique({
where: { id: token.sub },
});
if (!user) return token;
token.role = user.role;
return token;
},
},
adapter: PrismaAdapter(prisma),
...authConfig,
}); auth.config.ts import { NextAuthConfig } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { $LogInSchema } from "./lib/validation";
import prisma from "@/lib/prisma";
import { User as PrismaUser, UserRole } from "@prisma/client";
import { JWT } from "next-auth/jwt";
declare module "next-auth/jwt" {
interface JWT {
role: UserRole;
}
}
declare module "next-auth" {
interface User extends PrismaUser {}
}
export default {
session: { strategy: "jwt" },
pages: {
signIn: "/auth/login",
error: "/auth/error",
},
providers: [
CredentialsProvider({
credentials: {
email: { label: "Email", type: "email" },
phone: { label: "Phone", type: "tel" },
},
async authorize(credentials, req) {
const validatedFields = $LogInSchema.safeParse(credentials);
if (validatedFields.success) {
const { email, phone } = validatedFields.data;
const user = await prisma.user.findFirst({
where: {
OR: [{ email }, { phone }],
},
});
if (!user) return null;
return user;
}
return null;
},
}),
],
} satisfies NextAuthConfig; |
Guys sorry to bother but how about my case? export default NextAuth(authConfig).auth(middleware);
async function middleware(req: NextRequest) {
const url = req.nextUrl;
const hostname = getHostname(req.headers.get("host")!);
const path = getPath(url.pathname, url.searchParams.toString());
const isBusSearch = isBusSearchPath(path);
if (isBusSearch) {
const [, origin, destination] = isBusSearch;
return NextResponse.redirect(`${MONOLITH_LINK}/onibus/${origin}/${destination}`);
}
if (shouldRewriteRootApplication(hostname)) {
const rewrittenUrl = getRewrittenUrl("/home", path, new URL(req.url));
return NextResponse.rewrite(rewrittenUrl);
}
const subdomain = getSubdomain(hostname);
if (subdomain !== "www") {
const rewrittenUrl = getRewrittenUrl(`/${subdomain}`, path, new URL(req.url));
return NextResponse.rewrite(rewrittenUrl);
}
}
function getRewrittenUrl(basePath: string, path: string, reqUrl: URL): URL {
return new URL(`${basePath}${path === "/" ? "" : path}`, reqUrl);
} The problem is the auth seems to run before the middleware. |
Hi @AmphibianDev. It seems like you are using CredentialsProvider. I am afraid I won't be able to tell the issue for this. I am using EmailProvider. I can point out that the |
@jainmohit2001 You gave me hope again, I was literally just writing about giving up, and your message popped up, I even started to have PTSD when I opened the auth's files 😭 import log from "logging-service" //-> Cannot find module 'logging-service' or its corresponding type declarations.ts(2307)
export default NextAuth({
logger: {
error(code, ...message) {
log.error(code, message)
},
warn(code, ...message) {
log.warn(code, message)
},
debug(code, ...message) {
log.debug(code, message)
}
}
}) And I added the below code into the auth.ts, but I got nothing in the console. NextAuth({
debug: true,
logger: {
error(code, ...message) {
console.log(`${code} ${message}`);
},
warn(code, ...message) {
console.log(`${code} ${message}`);
},
debug(code, ...message) {
console.log(`${code} ${message}`);
},
},
... |
@AmphibianDev I think this is almost 100% a workaround, but it seems to work and is why my one currently works. If you are running it in a non-edge environment, I think this approach is fine. To check this actually works, I've made the changes and made a PR for this. Others can check the code here for an easier to read breakdown of the required changes but the explanation below might be useful Fix PR ...For AmphibianDev
import prisma from "@/lib/prisma";
import { NextAuthConfig } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { $LogInSchema } from "./lib/validation";
+ import { getUserById } from "./data/user";
+ import { PrismaAdapter } from "@auth/prisma-adapter";
export default {
providers: [
// Your provider stuff from before... Nothing has changed here
],
+ // We have moved the callbacks into this file
callbacks: {
async session({ session, token }) {
if (token.sub && session.user) {
session.user.id = token.sub;
}
if (session.user) {
session.user.id = token.sub;
session.user.role = token.role;
}
return session;
},
async jwt({ token }) {
if (!token.sub) return token;
- const user = await prisma.user.findUnique({
- where: { id: token.sub },
- });
+ const user = await getUserById(token.sub);
if (!user) return token;
token.role = user.role;
return token;
},
},
+ // We have moved the session into this file
session: { strategy: "jwt", maxAge: 365 * 24 * 60 * 60 },
+ // We have moved the jwt into this file
jwt: { maxAge: 365 * 24 * 60 * 60 },
+ // We have moved the adapter into this file
adapter: PrismaAdapter(prisma),
} satisfies NextAuthConfig;
import NextAuth from "next-auth";
import authConfig from "@/auth.config";
export const {
handlers: { GET, POST },
auth,
signIn,
signOut,
} = NextAuth({
pages: {
signIn: "/auth/login",
error: "/auth/error",
},
...authConfig,
});
//... Other Imports
import NextAuth from "next-auth";
import authConfig from "@/auth.config";
const { auth } = NextAuth(authConfig);
export default auth((req) => {
const { nextUrl } = req;
const pathname = nextUrl.pathname;
const isLoggedIn = !!req.auth;
const isAdmin = req.auth?.user?.role === "ADMIN";
console.log(req.auth?.user); // => { email: 'myemail@gmail.com' }
//... The rest of your code here
})
import prisma from "@/lib/prisma";
export const getUserById = async (id: string) => {
try {
const user = await prisma.user.findUnique({ where: { id } });
return user;
} catch {
return null;
}
}; So whats the workaround?Basically it looks like the workaround is to import a function that calls prisma independently and then just await that function. Doing this seems to solve the issue. If this is a valid work around this 100% needs documenting, and if it is, it really needs to be made clearer. |
Hi @ConnorC18. Thanks for helping out @AmphibianDev with the PR. Appreciate it!! A quick question: |
No worries! So, I am exclusively looking at this from a Non Edge standpoint, as that is what myself and @AmphibianDev are both using in this case. As far as I can see, it builds fine and runs (with the exception of the session callback having a es-line type issue in @AmphibianDev s case, but I believe that is because he needs to update his next-auth version, as I do not have this issue with the same approach). After building, the following successful output can be seen for @AmphibianDev s project |
Well seems like Prisma can work in edge runtime. I am using Edit: I am also using a DB adapter! Needed in EmailProvider. |
Big thanks to ConnorC18 for the amazing help! ⭐⭐⭐⭐⭐
./auth.config.ts:42:30
Type error: Property 'token' does not exist on type '({ session: Session; user: AdapterUser; } | { session: Session; token: JWT; }) & { newSession: any; trigger?: "update" | undefined; }'.
40 | ],
41 | callbacks: {
> 42 | async session({ session, token }) { Right again, this happens on |
Also quick note, Prisma is beginning to release edge compatible clients. In their latest Just remember to use |
i'm facing the same issue. So far the only solution i found is to use Prisma on the edge following this article: https://www.prisma.io/blog/database-access-on-the-edge-8F0t1s1BqOJE. |
Yeah so historically the only option has been Prisma Accelarate. This is just a db connection pooler behind an HTTP endpoint, so you all you needed was an http client (fetch, axios, etc.) and that's something you find in any runtime (edge, node, etc.). But now they're seemingly slowly but surely shipping "real" edge runtime support. Upgrading the |
@ndom91 do you know if Prisma edge client is compatible with Supabase Supavisor https://github.com/supabase/supavisor/blob/main/README.md. |
No that won't work unfortunately. Prisma "edge client" (i assume you mean the preexisting accelerate thing?) is just an http client sending http requests back n forth to prisma, who on their end pool the connections and respond back with http. The supabase supavisor seems to be an actual postgres pooler that works over the postgres protocol, not http |
Hello guys, I already implemented the solution proposed by @ConnorC18 and checked the @AmphibianDev repository, I have exactly the same implementation and the same versions of next-auth and prisma, I also separated the functions that use Prisma into independent functions, but now I am having this problem (with Prisma Adapter it doesn't work either)
|
Hello, any workrounds? im facing this issue too #9836 (comment) |
Hey folks, this issue seems to have gotten a bit off track.. Initially the issue was about session data not being available in middleware, right? And then it shifted towards prisma not working in edge environments. I think we've all gotten to the bottom of the prisma issue, right? If not, here's my current understanding - using Regarding the middleware import { auth } from "./auth"
export default auth((req) => {
console.log("middleware.auth", !!req.auth)
})
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
} If you're having problems that aren't related to the original middleware session issue, please open a new issue. To the latest commenters, @SebastianNarvaez11 this is an error you're throwing yourself because your You can enable @renatoastra can you provide more details about your setup and which versions of next-auth and next.js you're using? Thanks everyone 🙏 |
Here are the versions of my libraries:
While debugging my callbacks and middleware, I discovered the issue. It appears to be related to the prisma query on the JWT callback function, although I'm unsure why. However, placing my Prisma query within a try-catch block resolved the issue! Here is the code:
|
When using the However, if I instead use the following: https://github.com/nextauthjs/next-auth/blob/main/apps/examples/nextjs/middleware.ts#L4 Then returning |
Thanks @ConnorC18
|
I tried the recommended work arounds such as what @ConnorC18 said here but now I am getting a whole different error together. Seems to be related to middleware once more. Any ideas on how to fix this? ⨯ Error [ReferenceError]: Cannot access 'WEBPACK_DEFAULT_EXPORT' before initialization
|
Hey guys, I found what worked for me was to define the session callback in both auth.ts and auth.config.ts. The Credentials and other callbacks is defined in auth.ts. Now I can retrieve the custom field in the session on both the server and client as well as in the middleware.ts. I am not sure why this works, but here is the code if anyone wants to give it a try (using next-auth-5.0.0-beta.15):
auth.ts
middleware.ts
|
Just want to reiterate, the splitting of your auth config into separate Example prisma edge setup: https://github.com/ndom91/authjs-prisma-edge-example |
Big thanks to you @ConnorC18 i looked at your commit at the @AmphibianDev repo how u did it so i fix at mine and it works for me to. |
問題描述: auth.js callback 中 token, session 的相關處理 應該可以影響到在 req.auth 應該顯示的資訊 但僅能顯示 user 的 name, email, image 三個欄位 解決方式: 將 callback 放在 auth.config.js 中,即可正常顯示完整資訊 nextauthjs/next-auth#9836 (comment)
its work !! thank you !!! |
if anyone is still struggling with this issue (like me for around 2h) remember that after correctly splitting up your config, when the JWT strategy is enabled all the extra properties are accessed through This was the issue for me, decided to share it here (yea a silly mistake) // src/auth.config.ts
// ...
authorized: ({ auth }) => {
return !!auth?.user.id;
},
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id, // this should be TOKEN.ID
},
}),
// ... |
this works for me |
Closing, as #9836 (comment) explains this issue perfectly. Not much to document in my opinion (apart from what we wrote already here: https://authjs.dev/guides/edge-compatibility), as this is a perk of the split config that we are forced to do, as If anybody has a suggestion on how to improve the exisiting page, feel free to open a PR, thanks! |
used old method of setting role in jwt token and it works auth file
middleware
|
hi @JorgeMadson, i have same problem with subdomain, https, authjs |
I solved this issue for myself. I have a separate auth.config.ts and auth.ts, and in middleware does The fix was to move the So in ...
callbacks: {
async session({ session, token }) {
if (token.user)
session.user.id = token.user.id
return session
},
},
... And in ...
export const { auth, handlers, signIn, signOut } = NextAuth({
...authConfig,
callbacks: {
...authConfig.callbacks,
async jwt({ token, account, profile, user }) {
// DB calls here
}
}
}) |
Environment
System:
OS: Windows 11 10.0.22631
CPU: (12) x64 AMD Ryzen 5 3600 6-Core Processor
Memory: 7.60 GB / 15.95 GB
Binaries:
Node: 20.11.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.19 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
npm: 10.2.4 - C:\Program Files\nodejs\npm.CMD
Browsers:
Edge: Chromium (120.0.2210.91)
Internet Explorer: 11.0.22621.1
npmPackages:
@auth/prisma-adapter: ^1.1.0 => 1.1.0
next: 14.1.0 => 14.1.0
next-auth: 5.0.0-beta.5 => 5.0.0-beta.5
react: ^18 => 18.2.0
Reproduction URL
https://github.com/SebastianNarvaez11/TesloShop
Describe the issue
I am trying to get the custom field "role" in the middleware using req.auth but the custom fields that I added when creating the session previously are not there
In middleware.ts
console.log(req.auth)
:but with use
auth()
in the component it works :const session = await auth(); console.log(session)
:How to reproduce
My file
src/auth.ts
:My file
src/auth.config.ts
:My file
src/middleware.ts
, the problem is here:Expected behavior
In the middleware you should have access to the custom fields that you added when creating the session
The text was updated successfully, but these errors were encountered: