How to manually trigger next-auth to refresh the JWT? #4229
-
Hi Devs, I have a situation where the user can update their personal details and some of those details are also used to make up the payload of the JWT that is generated by the server. Therefore an action performed by the client can actually cause the token to contain stale data. I have been provided with an endpoint that will regenerate a new token on the serverside and return it to the client. So I would be able to hit this endpoint and get a new token after the user updates their details in this way. My question is how can I get next-auth to accept a new token and start using it for the current and subsequent sessions? I've already read through #371 but I've not seen a solution that will deliver the right behaviour in my case. Some additional info:
Even though next-auth has provided a way to get the jwt() callback to fire on command, it seems like I don't have a way to get control over the arguments passed to the jwt() callback. Therefore I don't see how I would be able to write any logic inside this callback to return a new token even if the token has not expired and is still valid etc. See below from the docs (I've inserted some comments to highlight my problem)
If anyone could point me in the right direction that would be a massive help, I'm not sure where to look at this point. I'm also not sure if the operation that I'm attempting to describe has a name (session mutation?) so even pointing me at some similar questions or threads that solve my issue under a different name would be great. Please ask me to clarify if I haven't provided enough of an explanation. Cheers. |
Beta Was this translation helpful? Give feedback.
Replies: 23 comments 57 replies
-
@MaxRandle did you also take a look at https://next-auth.js.org/tutorials/refresh-token-rotation ? |
Beta Was this translation helpful? Give feedback.
-
I have similar problem, and there is no working solution anywhere. So i had to make my own. eg.
Then in view where you receive api response you can do
And voila user is signed in :) |
Beta Was this translation helpful? Give feedback.
-
Bump on this issue. Our team still doesn't have a solution barring doing something potentially unsafe or hacky like trying to set the HttpOnly session cookie ourselves. |
Beta Was this translation helpful? Give feedback.
-
As a workaround to this I added a new CredentialProvider to my setup which simply takes the accessToken of the currently logged in user along with anything I need to alter the session. In my case I have an address form. Then in the submission of the address form I simply call A bit hacky but it works. |
Beta Was this translation helpful? Give feedback.
-
@toomus Solution worked for me with a little tweak: CredentialsProvider({
id: 'update-user',
credentials: {},
authorize(credentials) {
return { user: JSON.parse(credentials.user) };
},
}),
...
await signIn('update-user', {
user: JSON.stringify({ ...user, newProperty: true }),
}); Seems that when passing objects you need to serialize them as strings with JSON parse/stringify |
Beta Was this translation helpful? Give feedback.
-
A few people have suggested creating an additional custom credential provider that accepts the old token, then calling Unfortunately it may not provide the behaviour you want because calling I'm tempted to mark this as the solution because the longer I think about the more this starts to sound like expected behaviour. However Ideally I'd like someone from the NextAuth team to endorse this as the accepted solution or suggest a better way because ultimately this is a hack. The solution I want is to be able to control arguments or options passed to the Some example code of how this could look: useSession call
jwt callback
This way I can just manually refetch any data that could have changed as a result of the session updating. This is dead simple and I'm convinced it would provide the right behaviour as well as being easy to implement. |
Beta Was this translation helpful? Give feedback.
-
Is there an issue for this? |
Beta Was this translation helpful? Give feedback.
-
It would be great if there was a method on the server like |
Beta Was this translation helpful? Give feedback.
-
Unfortunately - after a week of struggle - it seems to me like token refresh is not really supported in this framework. The token might be refreshed by either a server side call that pings the session (such as As I see, Anyways, at the current state it is very-very hard to get to a consistent client with token rotation, and the problem mentioned originally is also a blocker to have at least some kind of workaround. |
Beta Was this translation helpful? Give feedback.
-
I think this is the very same problem I have, opened a discussion couple of days back: #6489 |
Beta Was this translation helpful? Give feedback.
-
Also facing this issue with a NextAuth + Cognito integration. Cognito supports custom attributes which we are using to store additional info necessary to connect to a backend API. But as it isn't possible to manually refresh these tokens, users have to log out and in again to get the updated token. We'll be adding an additional fetch request to get the info from a backend API instead for now. |
Beta Was this translation helpful? Give feedback.
-
There are many threads and issues posted on this topic, and for quite some time with no action. I'm afraid I've reached the point where I'm going to start down path of implementing OAUTH flow on my own because while auth.js a great effort from great people in their spare time, I'm sure, it's not useful for for anything other than hobby projects when missing basic functionality like the issue posted here (i.e., being able to initiate jwt and session callbacks being called from the client). It's a non-starter that the user should need to log-in/out or refresh the page because they, for example, changed their user handle (or some other prop that app decides to attach to jwt) which need to be reflected in updated session state. |
Beta Was this translation helpful? Give feedback.
-
I was able to fix the issue in the Nuxt Auth implementation here: I think exactly the same step needs to be fixed on the server side request with NextJS. Here is the function "getSession()" called: Inside this function a fetch is made to the I don't know how to fix it in NextJs but I was able to get it working in Nuxt. You somehow need to update the server side context and copy over the cookie header. |
Beta Was this translation helpful? Give feedback.
-
For those that stumble upon this in the future, here's my partial-solution (for a Next.js web app using NextAuth & Prisma) Use case:allow a user to update information on their "profile"/"user", in this case the user's name Problem:"name" is stored inside my JWT, and after updating the user within the database, the JWT is not updated, causing frontends to display out of date "names" Solution:Use the session callback to modify calls to getServerSession ( or In my callbacks: {
session: async ({ session, token }) => {
// NOTE: this is only necessary because this is the ONLY point where
// new info from the DB is pulled into the JWT, if there is any
// ideally, there would be a separate refresh endpoint, but NextAuth doesn't yet have one.
// If there is one, remove this since it adds 1 query to every API call
const user = await prisma.user.findUnique({
where: {
id: token.sub,
},
});
return {
...session,
user: {
...session.user,
name: user?.name,
id: token.sub,
},
};
}, Then, you can call In the frontend, you can call Note: Either method may need a hard refresh of a frontend client to update the Caveats:This is inefficient and will produce 1 additional query to your database on every session validation or fetch. The ideal solution is to have a separate "refresh" or "revalidate" JWT API, but this is not supported out of the box now from what I can tell. Creating a new provider is a way to achieve this as suggested above, but I'd rather not be manually managing these things myself. |
Beta Was this translation helpful? Give feedback.
-
Is there a solution? Seems like none and everyone rolling their own secure or insecure. No workaround due to concerns of unideal or unsafe probably only makes everyone implement worse security. |
Beta Was this translation helpful? Give feedback.
-
Any update on this issue ? Edit: I found a solution working for my case, here is the code : On the frontend, create a refresh function : const refreshSession = async () => {
await fetch("/api/auth/session?refresh=true", {
method: "GET",
headers: { "Content-Type": "application/json" },
});
await signIn('email', { redirect: false });
} First call will get the session through the API. This triggers jwt and session callbacks. I add a refresh param to differenciate the call. Then, in my jwt callback (or session callback depending on your configuration/needs): async jwt({ token, user, isNewUser }) {
if (req.query.refresh) {
const refreshedUser = await getUserById(token.user.id) // refresh user from db or whatever you need
token.user = refreshedUser
}
return token;
} Also updating in the session callback : async session({ session, token }) {
session.user = { ...session.user, ...token.user }
return session;
} Finally, the last call on the frontend will refresh the await signIn('email', { redirect: false }); |
Beta Was this translation helpful? Give feedback.
-
Just happened to stumble upon this solution to update session: https://next-auth.js.org/getting-started/client#updating-the-session |
Beta Was this translation helpful? Give feedback.
-
The Just wondering though, why wouldn't the adapter be automatically called when the update is triggered? Currently, I have to manually call the adapter but feels like this should be in the source code: const adapter = AuthRestAdapter();
export const authOptions: AuthOptions = {
adapter,
providers: [...],
...
callbacks: {
async jwt({ token, user, trigger }) {
const newToken = token;
if (trigger === 'update' && token.sub) {
const latestUser = await adapter.getUser(token.sub);
if (latestUser) {
user = latestUser;
}
}
if (user) {
newToken.property1 = user.property1;
newToken.property2 = user.property2;
}
return newToken;
}
},
...
} |
Beta Was this translation helpful? Give feedback.
-
Is there a way to do the same via
does not set a |
Beta Was this translation helpful? Give feedback.
-
I got this manually updating session token to work, but is there a way to manually update the token of another user, rather than the current user? The use case is I want a Super admin to be able to update another user's admin role down to a normal user role (removing permissions), but I want to have that select user by ID to have their permissions revoked asap, instead of waiting for that user to manually update their session. |
Beta Was this translation helpful? Give feedback.
-
This is how I manual set Token in server component.
|
Beta Was this translation helpful? Give feedback.
-
For NextAuth, solution is like: const { data: session, status, update } = useSession() Any equivalent solution for SvelteKitAuth? |
Beta Was this translation helpful? Give feedback.
-
For people still interested in this topic. NextAuth now has documentation on refershing the token for Google with both JWT and database strategy: https://authjs.dev/guides/refresh-token-rotation. This seems to be new since NextAuth5? It is well written and works. I didn't test with Prisma like they do as I use MongoDB but I guess it should still work |
Beta Was this translation helpful? Give feedback.
Just happened to stumble upon this solution to update session: https://next-auth.js.org/getting-started/client#updating-the-session
This seems to solve exactly what we are trying to solve here. @MaxRandle