IdTokenExpired on using convexAuthNextjsToken in production
Error: {"code":"IdTokenExpired","message":"Expired: ID token expired at 2024-08-27 01:49:03 UTC (cur
63 Replies
This sounds unexpected since the auth library should be handling refreshing the tokens for you. I'll try and reproduce to see if there's a bug on our side, but could you share any more details on your set up? Also clearing cookies will likely temporarily solve this by forcing you to go through the full auth flow again
@sshader ok so, I setup google oauth on convex auth, once you login with google, then come back to site later it shows this error always. My 3 projects are broken.
In development. it shows error too but it upon refresh it get fixed but in production it stays broken
Do you have any logs or error messages you can share (client side logs, convex dashboard logs)?
What version of Convex + Convex Auth are you using?
"convex": "^1.14.0",
Error: {"code":"IdTokenExpired","message":"Expired: ID token expired at 2024-08-15 15:13:26 UTC (current time is 2024-09-06 19:50:37.295413176 UTC)"}
at m.queryInner (/var/task/.next/server/chunks/442.js:62:74422)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async m.query (/var/task/.next/server/chunks/442.js:62:73826)
at async P (/var/task/.next/server/chunks/258.js:1:14870) {
digest: '4279888865'
}
this is in vercel logs
convex prod logs:
Sep 07, 01:20:02
M
auth:store
error
'Invalid refresh token'
I'd recommend upgrading to latest Convex (1.15.0) or at least 1.14.4 + clearing cookies
@sshader same issue
how come in dev, full reload fixes the issue
aah did you guys abandon this project lmao
Can you describe more of what you're seeing and some potential steps to reproduce? That looks like a completely different error from before
I just ran into this too, the original error from OP that is
I'm only running dev, haven't tried in production. The second error described didn't happen for me. But it seems
convexAuthNextjsToken()
is returning a stale token, and presumably getAuthUserId()
is then throwing. But on refresh everything works.Cool -- sounds like this is an error thrown on the Next server during SSR then?
Yeah, it's a server component
I'm also occasionally coming across this in dev and production.
It seems to be when the token is somewhat stale (always happens when returning to work the following day). The first attempt at accessing the token fails, but upon refreshing the page, it refreshes the token and continues as expected.
This is in SSR using
isAuthenticatedNextjs()
. It seems that method is throwing the error, not when subsequently using the token it returns, causing the page render in Next to return a 500.
This is using convex@^1.15.0 and @convex-dev/auth@^0.0.61
I'm curious if @erquhart and @shea also have isAuthenticatedNextjs()
in the same file, as I suspect its that method, not convexAuthNextjsToken()
.
I'm also using convexAuthNextjsToken()
, but my stacktrace leads me to isAuthenticatedNextjs()
, and this seems to make more sense. The token fetching works fine, but authenticated status is unable to be successfully determined from it as it requires refreshing.const { signIn } = useAuthActions();
const [flow, setFlow] = useState<"signIn" | "signUp">("signIn");
const { toast } = useToast();
const [submitting, setSubmitting] = useState(false);
const storeAdmin = useMutation(api.admin.storeUser);
const router = useRouter();
const renderForm = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
setSubmitting(true);
const formData = new FormData(event.currentTarget);
const email = formData.get("email") as string;
const password = formData.get("password") as string;
console.log("Form Data:", { email, password });
try {
if (flow === "signUp") {
// Sign in the user first to ensure authentication
await signIn("password", formData);
// Now call the storeAdmin mutation
await storeAdmin({ user: { email, name: "Admin", password, role: "admin" } });
} else {
await signIn("password", formData);
}
router.push('/admin/dashboard');
i am getting undefined and null
import { query } from "./_generated/server";
import { v } from "convex/values";
import { User } from "./type/userType";
export const getUser = query({
args: {
email: v.string(),
},
handler: async ({ db }, { email }) => {
const user = await db.query("users").filter(q => q.eq("email", email)).first();
return user || null;
},
});
@agun40 your issue appears to be client side. I have never had an issue there, only server side.
how can i solve the issues
This is my schema
// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
import { authTables } from "@convex-dev/auth/server";
export default defineSchema({
...authTables,
users: defineTable({
name: v.optional(v.string()),
image: v.optional(v.string()),
email: v.optional(v.string()),
emailVerificationTime: v.optional(v.number()),
phone: v.optional(v.string()),
phoneVerificationTime: v.optional(v.number()),
isAnonymous: v.optional(v.boolean()),
// other "users" fields...
role: v.optional(v.string()),
}).index("email", ["email"]),
admin: defineTable({
email: v.string(), // Add the email field
name: v.string(),
tokenIdentifier: v.string(),
}).index("by_token", ["tokenIdentifier"]),
students: defineTable({
email: v.string(),
role: v.string(),
password: v.string(),
}).index("email", ["email"]),
teachers: defineTable({
email: v.string(),
role: v.string(),
password: v.string(),
}).index("email", ["email"]),
});
this is my mutation function
export const signUpAdmin = mutation({
args: {
email: v.string(),
name: v.string(),
password: v.string(),
},
handler: async ({ db }, { email, name, password }) => {
// Hash the password
const hashedPassword = await bcrypt.hash(password, 10);
// Insert the admin user into the admin table
await db.insert("admin", {
email,
name,
password: hashedPassword,
tokenIdentifier: "", // Initialize with an empty string or generate a token
} as { email: string; name: string; password: string; tokenIdentifier: string });
},
});
not to be rude but If this is not fixed in 1 week i am migrating back everything to supabase. Its been too long this obvious bug in production. Not sure if you guys even care but this is frustrating cause my 2 clients are bugging me.
Are you using
isAuthenticatedNextjs()
. Could that be what's throwing in your case?getNextjsAuthTOken() something
const user = await fetchQuery(
api.users.viewer,
{},
{ token: convexAuthNextjsToken() }
);
culprit^
After reviewing the code, I'm not sure how it could be throwing on either of those methods directly.
My stacktrace must be incorrect. The error must be thrown when failing to refresh the token in some situations when making a query call using it.
https://github.com/get-convex/convex-auth/blob/30c4f2fcc91ab4e92084bd20b8094e68b3d3487a/src/nextjs/server/index.tsx#L78-L91
GitHub
convex-auth/src/nextjs/server/index.tsx at 30c4f2fcc91ab4e92084bd20...
Library for built-in auth. Contribute to get-convex/convex-auth development by creating an account on GitHub.
This appears to be the origin of the error being thrown. Unsure why refreshing isn't happening upstream in some cases.
https://github.com/get-convex/convex-backend/blob/fe8f698addd4fadcfe14bbd90f25c98a243313a5/crates/authentication/src/lib.rs#L124
GitHub
convex-backend/crates/authentication/src/lib.rs at fe8f698addd4fadc...
The Convex open-source backend. Contribute to get-convex/convex-backend development by creating an account on GitHub.
Whats odd is I don't see any errors logged in convex's backend.
upgrading to @convex-dev/auth@^0.0.65 and will observe.
Is there a way to configure the token ttl so this can be tested in a more rapid fashion?
no nothing upgrading seems to work, I tested it all.
I will try again
hi, can you help me with mine
@agun40 I see you created a separate support thread for your issue. Why don't we move the conversation there?
okay let go there sir
Can confirm. Upgrade did not solve. Stepped away for an hour, refreshed my browser, and the error was thrown. Refresh again, everything is fine.
I do see this in the convex logs
Cool thanks y'all for all the extra details -- I'll try and reproduce this myself. If one of you has a handy repro and wants to be extra helpful, turning on verbose logging (https://labs.convex.dev/auth/debugging#enabling-verbose-logging) and sending me browser logs + convex dashboard logs would help me investigate.
Debugging - Convex Auth
Authentication library for your Convex backend
Is there a way to configure the token ttl so this can be tested in a more rapid fashion?I think the configuration is here: https://labs.convex.dev/auth/api_reference/server#jwtdurationms (I've been setting this to like 1 minute myself when trying to reproduce various issues)
server - Convex Auth
Authentication library for your Convex backend
Ok, I'll reduce the ttl and add verbose logging to try and help diagnose.
@sshader i suspect
preloadQuery
/ fetchQuery
isn't awaiting the refresh and proceeding with a stale token. I've yet to see this on the client side with useQuery
et al.
the fact the problem doesnt emerge on the second attempt tells me that the refresh does resolve, and stores a new token, just not in time for the original request.
It doesn't look like the jwt config is taking.
auth.config.ts
Wait for deploy, then log out of app and back in, and here is the issued token in cookies, expiring in 1hr still.Sep 16, 21:49:00
M
auth:store
error
'Invalid refresh token'
I shared all this before too idk why we resending it if someone is not even actively looking into it
I've triggered the error again with verbose logging enabled, but it doesn't look any more verbose.
This is all from my
next dev
console output. I see nothing related to the error in convex logs.
@sshader if you have any other ideas on how I can assist, let me know.
Without being able to successfully reduce the ttl of the issued id token, it makes it difficult to bang on.Hi everyone, please remember our Guidelines and Code of Conduct, and we're a small team. If you're a Convex Pro customer, it's best to email via the Convex Dashboard for email support. All other support from the community is provided on a volunteer basis.
Thanks allen for the help so far -- I'm trying to set up my own repro as well
(btw I think you want
jwt: { durationMs: 60000 }
up a level instead of nested under session
, and this should be in auth.ts
when using Convex Auth instead of auth.config.ts
)
Aight -- new version of Convex Auth hopefully fixes this (0.0.67)I'll give it a spin.
ttl config is working and refresh seems to be happening flawlessly! I'll keep monitoring, but seems like its fixed.
Hmmm actually now I'm observing getting logged out automatically. If I login, then just let the page idle, it will flip back the the
<Unauthenticated />
view after a couple minutes (this is with a durationMs of 60000)
Althought I'm having trouble reproducing, so I'll keep observing...Definitely still happening. Logs in convex:
I think there might be a different bug where two things can race to use the same refresh token which is what I want to look into next
that would make sense. I have multiple server components that would try to fetch simultaneously on app load
I think it's fixed but now it logouts often.
@sshader let me know when you are ready for more testing. I reverted back to 0.0.65 due to the issue making auth state to fragile.
new convex auth does not fix
same error
Application error: a client-side exception has occurred (see the browser console for more information).
Error: {"code":"IdTokenExpired","message":"Expired: ID token expired at 2024-09-17 12:04:54 UTC (current time is 2024-09-17 23:17:20.734180922 UTC)"}
at C.queryInner (/var/task/.next/server/chunks/5167.js:1:30941)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async C.query (/var/task/.next/server/chunks/5167.js:1:30345)
at async m (/var/task/.next/server/chunks/3818.js:1:14828) {
digest: '3592468013'
}
Ok another version is out -- 0.0.68 with another attempt at this
Feels good so far. I did get one logout and a console error of "Convex Auth: Unexpected missing refreshToken cookie during client refresh" early on, but it hasnt resurfaced. May have been some latent state from the earlier session.
I've pushed it to prod and still see the logs peppered with "Invalid Refresh Token"
I don't know how its getting in this state, but once it is, its stuck there as nothing clears the cookie with the back refresh token value. So every request to convex tries to run a refresh routine and fails.
My best guess is that multiple synchronous queries executing a refresh and all requesting new refresh tokens. This introduces a race condition where a stale, invalidated token can get persisted to cookie storage. This then puts everything into a bad state which there is no recovery (short of manually deleting cookies) as the bad cookie value is never cleared once identified as bad.
However, this is speculative as I havent taken the time to dive into the code around this. Hopefully my uneducated musings based on observed behavior are of some help.
Hmm not clearing cookies on this is surprising to me -- if you happen to see this again and have the network tab open (can see any of the network requests and see if they're setting / clearing any of the relevant cookies), let me know.
Will also continue to try reproducing all these errors.
I'm also experiencing something thats hard to describe. Essentially in Route A with its own auth guard component in place links to Route B with different instances of the same auth guard, route B throws errors about being unauthorized, even though Route A wont present a link unless they are in a logged in state.
I'm happy to hop on a call and walk through this all if its helpful.
Not sure that my component layout/structure is the culprit. seeing some similar behavior just naving around the same component layout. It will just suddenly boot me out and (this time) successfully clear cookies.
You can see it thinks the token is invalid during a refresh, yet a bunch of queries resolve out with cache, then suddenly things start failing.
Thank you Allen for your help in fixing this so far. I'm still stuck with this error. Please any new solutions.
The worst of it all is that I cant even logout of my web app to be able to sign in and create new tokens.
This only happens on nextJS
This issue here is that in my middleware
This isAuthenticatedNextjs()) returns true;
This isPublicPage(request)) returns false;
But the refresh token is expired. So I don't know how to handle the logic from here onwards.
Or how to clear the token stored so it doesn't assume I have an active session.
@lexcodeit I'm still working through this with Convex support outside of this thread. Not experiencing some of your issues though. What version of convex auth are you using?
isAuthenticatedNextjs
is rather dumb, just evaluating if there is an auth token cookie present, so don't extend it too much trust. However, if everything is working properly, that token should be cleared if invalid, but you are likely evaluating it before that logic is executed.For a Next project with SSR and Convex Auth latest version, I do see this as well, specifically when I haven't touched the project in some time, so something with the refresh. If I switch tabs for a second and come back, it resolves (not sure if something is happening with the tab switching or if it's just time).
I see this too in our project
For a Next project with SSR and Convex Auth latest version, I do see this as well, specifically when I haven't touched the project in some timeHmm this is surprising for latest version of Convex Auth (this error message in particular). For folks with custom middleware handlers, make sure you're using
convexAuth.isAuthenticated
and convexAuth.getToken
in the handler (see https://labs.convex.dev/auth/authz/nextjs#require-authentication-for-certain-routes)
(I also want to call out that Convex Auth + Next.js SSA support is still experimental, so bug reports + patience while we address those is much appreciated)Server-side authentication in Next.js - Convex Auth
Authentication library for your Convex backend
├── @convex-dev/auth@0.0.71
│ └── @auth/core@0.31.0
Just ran dev server first time today, which is when it reliably happens, still happening.
I'm using
"@convex-dev/auth": "^0.0.69",
"convex": "^1.16.2"
I managed to just clear cookies manually whenever I run into the issue for now till I figure a better way out.
0.0.71 does have some improvements. 69 was especially problematic for me.
The behavior I'm observing is the session getting nuked because an invalidate refresh token is used, which causes all cookies to be deleted.
When you get the error, if you refresh the page it resolves right? That's what I'm seeing. I don't rely on cookies outside of whatever convex auth might be using, so that may limit the impact in my case.
No. I'm logged out as my auth cookies are deleted.
oh interesting, we're having different experiences then
Mine is just on initial load, presumably a failed token refresh or something, but on refresh I'm still logged in