-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Cannot modify JWT to refresh access_token #12454
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
Comments
I spent 2 days thinking I was doing something wrong, until I made a small example also, the token never updates. async jwt({ token, account, user }) {
console.log('JWT', token)
if (account && user) {
console.log('First time')
token.iteration = 0
token.expires_at = Math.floor(Date.now() / 1000 + 60)
}
if (Date.now() < token.expires_at * 1000) {
console.log('Still good')
return token
}
console.log('expired')
return {
...token,
iteration: token.iteration + 1,
expires_at: Math.floor(Date.now() / 1000 + 60)
}
}, After one minute, I just keep seeing next-auth version is: 4.24.11 |
As far as i understand, the docs say that when you update the JWT in This works when In any further invocations it seems to that even if you update the JWT and return the updated JWT from The only way i can think of is keeping access token and refresh token in a database table and manage it from there but this defeats the purpose of having JWTs. |
This is also present in the latest beta version: [email protected] Spent the last few hours trying to work out why my token refresh was always triggering! |
Seeing this too in |
So fast forward a few hours... and it's working for me now 😕 |
Mind showing your |
I spent hours trying to investigate this. In the end I've given up and rolled my own auth using iron session |
@8lane Here's a gist of my auth.ts (I make no claims about the cleanliness of it, but it seems to work) https://gist.github.com/TwoWheelDev/83d263b59f4587ae01f134ef0a7795cc |
Thank you 🙏 Aside from your
Using App Router |
I'm currently using export { auth as middleware } from "@/auth"
export const config = {
matcher: [
'/admin/:path*',
'/((?!api|_next/static|_next/image|.*\\.png$).*)'
],
} |
That's basically what I experience. Yes, it is possible to update the JWT, Yes, the updated JWT it gets passed to the session but at the next cycle, the JWT itself stands as it was post - login. For now. In https://github.com/rhufsky/authdemo I simulate that in the JWT callback by
Turns out that status stays "INITIAL" for each call and refreshCount stays zero, meaning that the JWT can not be updated. SOMETIMES however, the JWT can be updated, meaning the status goes to "REFRESH" and refreshCount is non - zero. It looks like there must be a minimum interval between two JWT updates. |
I had a similar Issue. check if this comment fixes it: #8138 (comment) It didn't work in the end for me |
Since OP doesn't use any Having said that I use a |
Tried a bit what @brechtmann suggested in #8138 , to no avail. While the proposed solution seems to be valid, for me it does not change anything. On the other hand I really think that there is some race condition, probably inside NextAuth. Most of the time an update of the the JWT does not work, however SOMETIMES it works out of the blue. |
Same Problem, NextJS 14.2.8, App Router |
I have a, maybe, related issue, not sure? So feel free to delete my comment if needed. I feel like it's related? |
I stumbled across the exact same problem. My sample just tries to narrow it down to prove that the JWT cannot be updated. |
Updated to "next-auth": "^5.0.0-beta.26", same problem. JWT cannot be updated. |
Just another try to find a solution. My callbacks: {
async jwt({ token, account }) {
console.log("############# JWT() #############");
console.log("current JWT");
console.log(token);
console.log("#############");
if (account) {
console.log("adding INITIAL status to JWT");
const initialToken = { ...token, status: "INITIAL", refreshCount: 0 };
return initialToken;
} else {
console.log(
`current JWT status: ${token.status} / ${token.refreshCount}`
);
console.log("adding REFRESH status / count to JWT");
const refreshCount = (token.refreshCount as number) || 0;
const refreshedToken = {
...token,
status: "REFRESH",
refreshCount: refreshCount + 1,
lastRefresh: new Date().toISOString().slice(0, 19).replace("T", " "),
};
return refreshedToken;
}
},
async session({ session, token }) {
console.log("############# Session() #############");
session.status = token?.status as "INITIAL" | "REFRESH";
session.refreshCount = token?.refreshCount;
return session;
},
}, When Subsequent invocations of Alas, when When debugging
const newSession = await callbacks.session({ session, token });
// Return session payload as response
response.body = newSession;
// Refresh JWT expiry by re-signing it, with an updated expiry date
const newToken = await jwt.encode({ ...jwt, token, salt });
// Set cookie, to also update expiry date on cookie
const sessionCookies = sessionStore.chunk(newToken, {
expires: newExpires,
});
response.cookies?.push(...sessionCookies);
await events.session?.({ session: newSession, token });
const payload = await jwt.decode({ ...jwt, token: sessionToken, salt });
if (!payload)
throw new Error("Invalid JWT");
// @ts-expect-error
const token = await callbacks.jwt({
token: payload,
...(isUpdate && { trigger: "update" }),
session: newSession,
});
I might be doing something terribly wrong, but to me it looks that there is a problem in auth.js that prevents a JWT from being updated. From searching around I sense that more folks are running into the same problem, As it is, I cannot reliably update an access token, which somehow defeats the purpose of an Oauth library. @balazsorban44 is there a chance to look into that case? Sorry for the inconvinience. |
Also running into this issue. Not of the workarounds seem to quite work. Note there's also an ongoing discussion here: #7558 |
After hours and hours of research and reading a number of threads here I came to the conclusion below, if this is wrong, I happily appreciate any suggestions:
My biggest request would be that the documentation https://authjs.dev/guides/refresh-token-rotation is updated to the reality. |
From my experience trying to implement nextauthv5 + keycloak the refetchInterval param in SessionProvider must not be 0.
|
Oh wow, yeah, that actually did the trick! It now has to poll the server from the client side before it will update, and if I load the page with an already expired token there's some weird race condition stuff where it will simultaneously fetch a couple of refresh tokens, but then it seems to come right... But anyway, it's a workaround at least until this is fixed properly |
That looks interesting. I believe that also some race condition makes the oroiginal code work in some rare cases. Anyway, I went for database strategy, which seems to work quite fine. |
I don't even use SessionProvider, what is the benefit/need of doing that? |
I don't use it much, but it's useful if you need direct access to your session data from a client side component. But now, apparently, I use it to update my store session token too |
AFAIK it's the only (or maybe just the most straightforward way) to auto update client side UI about being not authenticated. |
Yes, I had something like that. refreshAccessToken is called twice.
|
Is jwt refresh token support present or not? |
Well, it seems, with a bit of a workaround, yes |
x^### Environment
Reproduction URL
https://github.com/rhufsky/authdemo
Describe the issue
Cannot update JWT after initial creation at login time, shown by a simplified example. In the current state, it seems that I am unable to implement token refresh as described in https://authjs.dev/guides/refresh-token-rotation.
How to reproduce
Login and watch the
jwt()
callback. As a sample I create an arbitrary propertystatus
and set it to"INITIAL"
at the first invocation ofjwt()
.When
jwt()
is invoked for a second time, it returns a token withstatus: "REFRESH"
.The new value is never persisted, at the third invocation of
jwt()
,status
is still"INITIAL"
.Expected behavior
After every invocation of
jwt()
the returned token should be persisted.The text was updated successfully, but these errors were encountered: