auth-helpers: Invalid Refresh Token: Refresh Token Not Found
Bug report
Describe the bug
I’m currently getting Invalid Refresh Token: Refresh Token Not Found error in my Next.js middleware
const res = NextResponse.next();
const supabase = createMiddlewareSupabaseClient({ req, res });
const {
data: { session },
error,
} = await supabase.auth.getSession();
if (error) {
throw new Error(error.message);
}
A clear and concise description of what the bug is.
To Reproduce
I think the issue is pretty similar to this one:
https://github.com/supabase/gotrue-js/issues/323 Steps to reproduce the behavior, please provide code snippets or a repository:
- Go to ‘…’
- Click on ‘…’
- Scroll down to ‘…’
- See error
Expected behavior
To logout the user, or keep them signed in
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
System information
- OS: [e.g. macOS, Windows]
- Browser (if applies) [e.g. chrome, safari]
- Version of supabase-js: [e.g. 6.0.2]
- Version of Node.js: [e.g. 10.10.0]
Additional context
Add any other context about the problem here.
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 25
- Comments: 87 (12 by maintainers)
I’m not suggesting it’s a bug, but that it’s not a great developer experience. I’m trying to learn the Supabase framework and I’m building upon the Supabase Sveltekit example project that demonstrates auth flow.
What happens: After my token expires, if I try to load the homepage of my app, I’m met with a 400 error instead of my homepage. In the console I see the error
I honestly can’t tell which call from my codebase is triggering this error.
What I expect to happen: I would expect the example app to show where to gracefully handle errors of this nature and to redirect the user a login screen if its not possible to authorize the session.
I want to emphasize again, that I’m a brand new supabase user. I’ve got an mvp of my app going and I’m sporadically running into this Auth problem. After digging around in my code base trying to figure out where it’s happening I started googling which ended up on this thread.
Seeing this issue after switching from the next auth helper to the SSR package. Not breaking anything. Just causing logouts to be super frequent
Seems like we have a bug here (using try without catch) , so the exception
Invalid Refresh Token: Refresh Token Not Foundis thrown here when you call getSession()The typical way your users will see this problem is if they login, leave for a while, come back later (on the same browser) after their token has expired and try access a protected route, triggering a call to
getSessionorgetUsersomewhere in your code. This returns an error (the one in the title of this issue) rather than simply a null session (which would indicate the user is not logged in, according to the docs).Basically if a user doesn’t log out at the end of their session (which I would consider the typical behavior of most users) you are likely to get this issue.
You may be able to “fix” this by catching the error from
getSessionand setting the"clear-site-data"cookie (See MDN Docs) in the headers of your response (assuming you are caling getSession on the server side). WARNING: this will clear all cookies for your app. The sensible solution would be to delete just the expired supabase cookie, unfortunately this is not currently possible in production because the cookie name is unknown (see my comment above and issue https://github.com/supabase/auth-helpers/issues/719)Note this shouldn’t be an issue if you are calling supabase from the browser. Renaming cookies can be done using the example in the docs here. And you can easily use the
document.cookie = 'my-access-token='...after catching the error above. I haven’t tested this since we don’t touch supabase on the browserI think I found a reproducible one which produces a similar result. Could you please try this scenario?
await supabase.signOut().Disclaimer here is that my bug happens to have same result, but I never log out of the app nor do I turn off my server. My server is always online, and “Refresh token not found” happens after some time has passed. Also not sure what the expiry was set in cookie for the actual error scenario, but in actual scenario, the error persisted even if I closed the browser and reentered the website.
My current solution to bypass
Refresh Token Not Foundin production - this simply logs out the user: (part of middleware.ts)What did you increase this to?
I’m also running into this issue with
auth.getSession()when usingcreateRouteHandlerClientfrom@supabase/auth-helpers-nextjs+1 for this issue! I’m having it in the dart client ever since I cloned the user_management_example project and have to sign in using the magic link every time.
I believe the issue is that you have info in your cookies that references a deleted user.
Any updates on this? Our users get signed out at random times because of this and it’s a big issue for our app.
OK thanks for this insight. I’ll check the code there.
I encountered this error during testing due to being logged in with a cookie from a user I deleted from my database. I seem to have fixed it with this workaround, which clears all Supabase-related cookies if this error is thrown:
@NickG-NZ - The problem is that it happens in a lot of non-typical circumstances, and there is also no way to “catch” the problem.
J
@silentworks
I just want to add some context to what’s going on here because it is fundamentally not resolved. If you log in a user, then wait until the JWT expires (typically this happens if waiting overnight and come back the next day), the next call to
getSessionwill throw this error:Invalid Refresh Token: Refresh Token Not Found. This is “expected” because the token has expired but the browser is still sending the cookie because you never logged out (and therefore never deleted the cookie).Here’s where the problem comes though: The way I would handle this (since the supabase team refuses to implement anything elegant), is to simply catch the error and delete the cookie. This seems easy enough but: Deleting the cookie requires you to know the name of the cookie, which is not possible unless you gave it a custom name.
Unfortunately giving the cookie a custom name (by passing
cookieOptionstocreateServerClient) is broken (See my issue here: https://github.com/supabase/auth-helpers/issues/719 and may also be related to this issue: https://github.com/supabase/auth-helpers/issues/717I don’t know how anyone else is handling this, but it is a complete road-block for us.
@mb21 you can supply your own debug logger in the latest version of supabase-js
https://github.com/supabase/gotrue-js/releases/tag/v2.52.0
I’ve just re-read all the messages here and now I’m wondering what the actual issue is? All the scenarios provided seem to lead to the same error but the developer should be handling the error in their app. This isn’t something that supabase-js or auth-helpers should manage as this is down to error management in your app itself. Please reply to this message with what you expect to happen when your token has expired and not able to refresh due to whatever reason.
One of the places I found this error is when calling getSession, it sees the session as expired, then calls the gotrue api to try and refresh the session. Part of that process is trying to find a user that has the refresh token. If something goes wrong when searching for a user, it’ll return this error.
Can you look in your auth.refresh_tokens table and find an entry that matches the token?
I can reproduce it in production always. I just need to wait less than a day, I check the production site and it always fails on the first load.
From what I’ve found, it seems that the refresh token workflow works well until supabase/ssr decides to split the cookie in two chunks. Maybe the refresh token code misses to handle this situation.
In my case, the refresh token workflow works well with email login, but it doesn’t work properly with google signin/up as it pulls all user info in cookies and it gets split.
I didn’t found time to investigate this further and submit a PR yet, so take it with a grain of salt. In the meantime, going back to old auth-helpers package helps, but this would be really awesome for the refresh token workflow to work again reliably with supabase/ssr - because as of today users are forced-unlogged as soon as the JWT token expires (1h by default)
Ugh, and still no good solution to this problem? Because I tried everything I found in github issues, reddit and there is still no valid workaround it seems.
You nailed it. Note also that the cookie names generated by the SSR package include a random hash. So even if you want to manipulate them manually you can’t because you don’t know the name.
My preference would be that supabase automatically deletes the expired cookie and returns a null session (indicating the user is not logged in).
Note that this problem can be resolved manually now that the issue with setting a custom cookie name has been fixed. (You can set your own name for the cookie by passing an option to “creatServerClient”)
This means if this error occurs, you can just delete the cookie. And follow what ever your normal flow is for unauthenticated users.
Alternatively you can use the solution mentioned above and just remove all cookies starting with “sb-”. This is the solution we initially implemented to get around the problem
I was simply away from my system for a while and my app was running in the dev mode. I was greeted with this error.
I am using the new
@supabase/ssrpackage.Found this thread after encountering the same error following the official docs here: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#managing-session-with-middleware
As was already described by others, the error happens after being inactive some time.
Nothing against the code, but this looks more like a workaround than an actual fix, right? 😅
I don’t understand the underlying mechanism in detail, but I’d expect something like this to work:
I tried redirecting, rewriting, refreshing the session and logging the user out, but didn’t have any success. It would be great if we could get an updated example in the docs that shows a way to handle this error gracefully.
I posted a fix for this in https://github.com/supabase/auth-helpers/issues/691
This is reproducible with a local supabase with jwt_expiry turned down to 60 (or some other low number) and the default app created with
Here it is after first refresh:
And then refreshing again the table stays the same and you get a ton of these errors. Here are the debugger logs
debugger_output.txt
npx create-next-app -e with-supabase. The first refresh goes fine, although 10 refresh tokens get created: Here is refresh_tokens table before the initial refresh:At that point you get logged out of the app.
Same here - reminds me of an original bug in auth-helpers. Logs you out, in my case “token already used”.
the issue is still there. Any solution or workaround?
@wdavidturner I have the same issue, it happens when the auth token expires but the user is still logged in.
@seho0808 Thank you for providing the solution. I’m facing the same issue.
But is this also a solution, or will it only make the issue very less like to happen? So in the example of this max seconds being a week, will will get the error again if we logon to the app only to open it 8 days later…?