-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
Can't use auth() to get values from jwt() callback in v5 #9122
Comments
I've encountered the same issue, and it would be fantastic if it worked as described in the documentation. I aim to avoid exposing the access token to the client. As far as I understand, there isn't a way to obtain the up-to-date JWT in server calls. Although there's a getToken method, it only retrieves the JWT from the request, which might require updating (e.g., refresh token rotation). Getting the updated JWT directly from auth() would resolve this. |
Just ran into this as well after upgrading from a previous beta version. This is a pretty critical bug. |
I also met the issue and figured out that the migration guide of this part was a little misleading. After tracing the source code, I found that the If we want callbacks: {
session({ session, token }) {
// token is the returned value of `jwt()`
return { ...session, ...token }
// Can just return token if you want.
}
} |
@judewang The problem with this approach is that the unencrypted token is exposed to the client. |
@czymstef I supposed we can avoid exposing the token without using BTW the encrypted token is within cookie. |
As far as I know, there is still the /api/auth/session endpoint (used by |
So is there no way at the moment to get the raw token server-side? Seems pretty limiting |
@judewang go to https://next-auth-example.vercel.app/, which should run on next-auth v5 beta. Login using github, then in the developer console write: @alessandrojcm I think there is a way using |
@czymstef I tried https://next-auth-example.vercel.app and also got my token printed within the console. However when doing the same thing on my site, I still got a 404 error. I noticed that I didn't export the |
Yeah I noticed As per adding the token to the |
@alessandrojcm Mind sharing how you could get the token server side in v4? I thought that this was not possible, too (with refresh token rotation and all). @judewang If you don't export the handlers, then the callback endpoint does not exist, too, which makes logging in impossible, doesn't it? But we could only export the required handlers and just don't export the session one, or as @alessandrojcm suggested: Catch the call to /session and strip it. But who says that authjs won't add a method at a later stage which uses server actions? This is just not as the library is intended to be used; |
There is v4's getToken, though now that I think of it I am not entirely sure if that does execute And as per your second point, yes you are right one should not rely on patching |
Just to add, I am not quite able to get the |
Just to emphasize this again: I personally do not only want the raw unencrypted token, but have a refreshed one. In other words: I'm looking for a method to get the content of the If I understand the documentation correctly, |
I'm experiencing the same issue. Has there been any update or resolution? I'm attempting to retrieve user IDs using const session = await auth();
console.log(session.user) // { image: '...', email: '...', name: '...' } I ran through the code and figured out that this segment does nothing: next-auth/packages/next-auth/src/lib/index.ts Lines 76 to 83 in d7a1165
Because the supplied next-auth/packages/core/src/lib/actions/session.ts Lines 52 to 59 in d7a1165
|
@G4RDS I have the same issue, did you find any solution? |
@G4RDS does doing the module augmentation had any positive impact on solving the issue? or did you find a solution? |
If you need more info from the OIDC provider you can always get it by modifying the session object through the session: ({ session, token }) => {
// token has the object returned from the jwt callback
// here you can modify the session object as you please
session.user = {...session.user, id: token.user.id}
return session
},
jwt: async ({ account, user }) => {
// account has the user info from the OIDC provider
if (account) {
return {
user: {
...user,
// add whatever property from account
id: account.id
},
}
// @ts-expect-error
}
return user
}
}, You can then use module augmentation to get type completion. |
Is any of you guys by any chance using the drizzle-adapter and have the extended session object working? |
Currently facing the same issue, does not feel safe including 3rd party token in the session object. |
I managed to get the getToken(...) to return the JWT with the following Route Handler: Intentionally didn't send in a salt param, typescript does not approve. But as @czymstef mentions, with this the token is extracted from the cookie, which makes the token potentially stale. --- EDIT --- import { getToken } from "@auth/core/jwt";
import { cookies } from 'next/headers'
export async function action() {
"use server"
const all_cookies = cookies().getAll();
const headers = new Headers();
all_cookies.forEach((cookie) => {
headers.set("cookie", `${cookie.name}=${cookie.value};`)
});
const req = {
headers
};
const secureCookie = process.env.NODE_ENV === "production";
const cookieName = secureCookie
? "__Secure-authjs.session-token"
: "authjs.session-token"
const jwt = await getToken({ req, secret: process.env.AUTH_SECRET!, secureCookie, salt: cookieName });
console.log(jwt);
} |
Hey, I'm facing the same issue. However, you can "access" the async session({ session, token }) {
session.user.id = token.id;
return session;
},
async jwt({ token, user }) {
if (user) {
token.id = user.id;
}
return token;
}, |
Has anyone found a way to access the JWT token server side / api routes? Upgrading to v5 really seems like a down grade so far. |
Not tried a API route, but managed to access the JWT via getToken(...) in a Next.js Route Handler and a Server Action (#9122 (comment)). All it does is decode the cookie with your AUTH_SECRET. It's a work around for sure but as long as you have the Request Headers available you should be able to use this method if thinking. |
Just as a note, the type error with using token in the session callback is due to the typing where it will either have a token (if using jwt) or a user (if using a database); you can get around the type error somewhat by using the in operator narrowing: session(sessionArgs) {
// token only exists when the strategy is jwt and not database, so sessionArgs here will be { session, token }
// with a database strategy it would be { session, user }
if ("token" in sessionArgs) {
return {
...sessionArgs.session,
user: {
...sessionArgs.session.user,
roles: sessionArgs.token.roles, // something you are bringing in from your hwt function return via the token
},
};
}
return sessionArgs.session;
} |
You can also augment the type declaration to get rid of the type error in a cleaner way. |
Yes good point! I was augmenting my session shape to avoid errors, didn't think of augmenting the session function args too. |
How did you augment your session shape to avoid errors @xiavn , can you provide the code please? |
@vineetkia You might find this page helpful buried deep within the docs - Module Augmentation. Essentially you declare a module for 'next-auth' (or any other module you might want to override and then redeclare the interface's with new properties, and then anywhere in your code that you use somethign that has Session, it will have all the new properties you are planning to include, so you don't have to fight typescript. declare module "next-auth" {
interface Session {
address: string
}
} It will merge in new properties. If you want to modify a nested object within you need to tweak slightly: declare module "next-auth" {
interface Session {
user: {
address: string
} & DefaultSession["user"]
}
} You can just inport |
Thanks to everyone for their help. For some reason I had to add more type checks to make it work, in case anyone wants a fully working auth.config.ts example ...
|
I switched back to "5.0.0-beta.4" @lukasb , and it worked fine for me. in 5.0.0-beta.5 they had this breaking change. I guess until they go under stable release the 5.0.0-beta.4 works fine for session({ session, token }) |
The documentation has changed. The bit that I originally quoted is now gone. (b5d5f20) The commit references another issue (#9329) that was created after this describing the same problem. Quoting a comment by @balazsorban44 made on that issue:
Seems like Would have appreciated some better communication seeing as this issue has gathered a lot of traction, but at the same time many people commenting here is not even commenting about the original issue that I described, so I can see due to the discussions that emerged here it may not be clear what this issue really was about. |
currently migrating to v5. The guides are EXTREMELY useless. almost ranted... Examples folks, ones that work. Ones that are current. sorry, nothing nice to say here, I guess I did rant.. |
Faced the same issue and the struggles with documentation about this use case. For me the only workable solution was to use getToken(), even though the docs say it is not recommended. |
On nextjs 14, I got the access_token in the rsc, actions and routes by creating a cookie in the jwt() function using cookies() from next/headers. Doing this ensured that my access_token can't be accessed from the client or by going to /api/auth/session. I also handled some situations like deleting my cookies on expiry syncing its expiry with my session cookies from next-auth. async jwt({ token, user }): Promise<JWT | null> {
const cookie = cookies();
if (user) {
const accessDecode = jwtDecode(user.accessToken);
const userProfile: User = {
id: token.sub,
name: user.name,
email: user.email,
image: user.image,
accessToken: "",
refreshToken: "",
username: user.username,
};
cookie.set("access-token", user.accessToken, {
expires: accessDecode.exp! * 1000,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
return {
access_token: user.accessToken,
expires_at: accessDecode.exp as number,
refresh_token: user.refreshToken,
user: userProfile,
};
} else if (Date.now() < token.expires_at * 1000) {
return token;
} else {
if (!token.refresh_token) {
cookie.delete("access-token");
throw new Error("Missing refresh token");
}
try {
const { data } = await axios.get(
process.env.API_URL + "/user/generate-new-refresh-token",
{
headers: {
Authorization: token.access_token as string,
refreshToken: token.refresh_token as string,
},
}
);
if (data.error) throw new Error("Bad request");
const accessDecode = jwtDecode(data.data.accessToken);
cookie.set("access-token", data.data.accessToken, {
expires: accessDecode.exp! * 1000,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
return {
// Keep the previous token properties
...token,
access_token: data.data.accessToken,
expires_at: accessDecode.exp as number,
refresh_token: data.data.refreshToken,
};
} catch (error) {
cookie.delete("access-token");
return null;
}
}
},
async session({ session, token }) {
if (token.user) {
// @ts-ignore
session.user = token.user as User;
}
return session;
},
},
session: {
maxAge: 60 * 60,
}, |
Environment
Reproduction URL
https://github.com/Celsiusss/nextauth-demo
Describe the issue
In the documentation, it says that:
I tried to test this, but could not get values from the
jwt()
callback to be returned byauth()
. It seems like the opposite of what this text says is true. Values from thesession()
callback is being returned, instead ofjwt()
. Not quite sure what the intended behavior really is, but I would love to access encrypted token values usingauth()
.How to reproduce
I have tried to create a minimal example in the Github link.
Here I am using
auth()
in a server component and in a route handler, to demonstrate it in two different ways.page.tsx
shows it being used in a server component.api/route.ts
shows it being used in a route handler.client.tsx
client component for signing in and using the route handlerauth.ts
registers an oidc provider and defines thejwt()
callback.Expected behavior
I expected to be able to use
auth()
to retrieve values from thejwt()
callback in server side components.The text was updated successfully, but these errors were encountered: