Open nuurcodes opened 3 years ago
hey @nuurcodes thanks for the issue, could you please test if you can reproduce with the latest supabase-js version v1.13.1
@awalias Setting the JWT expiry to anything less than 60 still causes the accessToken to update in a loop on v1.13.1
When I set the JWT expiry to 60, I was expecting the accessToken to automatically update every 60 seconds but it doesn't. I've tried logging supabase.auth.session()
and also listening to onAuthStateChange
Having the same issue here. I'm constantly needing to log back into my app, even though I've set the expiration date to be a week long and have autoRefreshToken
set to true. It seems like I need to re-enter my credentials even if the token is not actually expired (i.e. I need to re-enter my credentials even though a week has not passed since the last time I did it). This happens both on localhost and on my production website.
If autoRefreshToken
is true, I would expect the token to be automatically refreshed without needing to enter my credentials again. In other words, if I've logged in once, I should stay logged in unless I've explicitly logged out or cleared my cookies/cache.
Shouldn't this be on by default? https://github.com/supabase/supabase-js/blob/master/src/SupabaseClient.ts#L11-L12
I still see this issue on 1.15.0.
:tada: This issue has been resolved in version 1.15.1 :tada:
The release is available on:
Your semantic-release bot :package::rocket:
Sorry to dig out an old issue, but are we sure this is fixed? Despite initializing the Supabase client with autoRefreshToken: true
I have to double check session.expires_at
and initiate supabase.auth.refreshSession()
manually throughout my app. (on version 1.28.2)
There isn't much documentation on how autoRefreshToken
is supposed to work. But judging from the questions in the discussions section, I'm not the only one who is having trouble letting Supabase refresh expired JWTs.
Sorry to dig out an old issue, but are we sure this is fixed? Despite initializing the Supabase client with
autoRefreshToken: true
I have to double checksession.expires_at
and initiatesupabase.auth.refreshSession()
manually throughout my app. (on version 1.28.2)There isn't much documentation on how
autoRefreshToken
is supposed to work. But judging from the questions in the discussions section, I'm not the only one who is having trouble letting Supabase refresh expired JWTs.
How you catch session expires and and initiate supabase.auth.refreshSession() manually. Thanks
Still broken. autoRefreshToken
setting does nothing to actually trigger a refresh and you will keep setting the error in perpetuity until you manually reload the page.
Yeah this seems to still be happening, at least when running Supabase locally for development, working on a React Native app using Expo ->
LOG SB Res --> {"data": {"session": null}, "error": [AuthApiError: Invalid Refresh Token]}
Trying to figure out how long before it expires, and supabase.auth.refreshToken()
also throws an error once it has expired.
Can confirm this is also happening for me.
Hey everyone, we're investigating this issue and it would be great if yall can provide the supabase-js / gotrue-js versions that you experience this error on.
Hey everyone, we're investigating this issue and it would be great if yall can provide the supabase-js / gotrue-js versions that you experience this error on.
Version: "@supabase/supabase-js": "^2.1.3"
Experiencing this with these versions:
supabase-js: 2.10.0 gotrue-js: 2.13.0
UPDATE: For my case, I have found that the problem actually comes from nuxt-supabase: https://github.com/nuxt-modules/supabase/issues/137#issuecomment-1466514716
When I left the app running on the iOS simulator for a while and reloaded Metro, I encountered the error
Invalid Refresh Token: Already Used
@supabase/supabase-js: "^2.22.0" expo: "^48.0.10" (bare workflow)
I am also getting "Invalid Refresh Token: Already Used" @supabase/supabase-js: "^2.21.0"
I don't see previous invocations which might have used the token. And btw, isn't the refresh token supposed to be constant and used only to reissue access tokens as needed?
Also getting this in my RN project, constantly being signed out in a matter of minutes, anything we can do here?
Have you tried setting the jwt_expiry
in config.toml
to one week (the maximum allowed):
jwt_expiry = 604800
Hey everyone, i'm attempt to reproduce this issue using the expo user management example (https://github.com/supabase/supabase/tree/master/examples/user-management/expo-user-management) but i haven't been able to reproduce this. It would be great if someone has a repo to share or can outline the reproducible steps.
I'm running on "@supabase/supabase-js": "^2.24.0"
, and this is how i'm initialising the supabase client:
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
storage: ExpoSecureStoreAdapter as any,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
});
Yeah this seems to still be happening, at least when running Supabase locally for development, working on a React Native app using Expo ->
LOG SB Res --> {"data": {"session": null}, "error": [AuthApiError: Invalid Refresh Token]}
Trying to figure out how long before it expires, and
supabase.auth.refreshToken()
also throws an error once it has expired.
This response describes the issue pretty similarly to me – I'm running supabase locally using npx supabase start
, my client is initialized just like yours is @kangmingtay but with local supabase url and anon key.
I have a supabase.auth.onAuthStateChange
which runs on app init and whenever the auth state changes. typically the repro case is logging in then waiting until the token expires, usually this happens while the app simulator / the app is in the background on my mac. in this case, my onAuthStateChange
fires and receives a session with a jwt and refresh token. This triggers a fetch from my profiles
table, but that request fails with {"code": "PGRST301", "details": null, "hint": null, "message": "JWT expired"}
. subsequent reloads of the app also fire onAuthStateChange
with what looks like a valid session but the same error occurs when trying to fetch data from supabase. my guess is that this session is coming from the secure store.
cc @lewisd1996 @b2m9 @edgarsilva @uze for your repro cases?
fwiw, the refresh token that is the session with the expired jwt is still valid according to my local db. i looked this up using the auth.refresh_tokens
table. so my issue is slightly different from some of the above responses where even calling refreshToken()
errors out. my client is being inited with autoRefreshToken: true
though, so also confused why supabase isn't refreshing it automatically! supabase version 2.25.0
getting AuthApiError: Invalid Refresh Token: Refresh Token Not Found
right now as well; not sure if this is the same issue
We're also getting the Refresh Token: Refresh Token Not Found issue every time we try to refresh.
The issue was resolved after I updated the Supabase Nuxt package to ^0.3.1. Additionally, I had to clear my existing Supabase cookies, which allowed the functionality to work as intended.
Only way I am able to resolve this issue is uninstalling the app and installing it again. This occurs in local development and not in production.
Using React native with @supabase/supabase-js: ^2.37.0
Same happening for me. "@supabase/supabase-js": "^2.42.7"
Here my supabase client setup:
import { Database } from '../../../../supabase/types'
import { createClient } from '@supabase/supabase-js'
import * as SecureStore from 'expo-secure-store'
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as aesjs from 'aes-js';
import 'react-native-get-random-values';
import { replaceLocalhost } from '../getLocalhost.native'
if (!process.env.EXPO_PUBLIC_SUPABASE_URL) {
throw new Error(
`EXPO_PUBLIC_SUPABASE_URL is not set. Please update the root .env.local and restart the server.`
)
}
if (!process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY) {
throw new Error(
`EXPO_PUBLIC_SUPABASE_ANON_KEY is not set. Please update the root .env.local and restart the server.`
)
}
const supabaseUrl = replaceLocalhost(process.env.EXPO_PUBLIC_SUPABASE_URL)
// As Expo's SecureStore does not support values larger than 2048
// bytes, an AES-256 key is generated and stored in SecureStore, while
// it is used to encrypt/decrypt values stored in AsyncStorage.
class LargeSecureStore {
private async _encrypt(key: string, value: string) {
const encryptionKey = crypto.getRandomValues(new Uint8Array(256 / 8));
const cipher = new aesjs.ModeOfOperation.ctr(encryptionKey, new aesjs.Counter(1));
const encryptedBytes = cipher.encrypt(aesjs.utils.utf8.toBytes(value));
await SecureStore.setItemAsync(key, aesjs.utils.hex.fromBytes(encryptionKey));
return aesjs.utils.hex.fromBytes(encryptedBytes);
}
private async _decrypt(key: string, value: string) {
const encryptionKeyHex = await SecureStore.getItemAsync(key);
if (!encryptionKeyHex) {
return encryptionKeyHex;
}
const cipher = new aesjs.ModeOfOperation.ctr(aesjs.utils.hex.toBytes(encryptionKeyHex), new aesjs.Counter(1));
const decryptedBytes = cipher.decrypt(aesjs.utils.hex.toBytes(value));
return aesjs.utils.utf8.fromBytes(decryptedBytes);
}
async getItem(key: string) {
const encrypted = await AsyncStorage.getItem(key);
if (!encrypted) { return encrypted; }
return await this._decrypt(key, encrypted);
}
async removeItem(key: string) {
await AsyncStorage.removeItem(key);
await SecureStore.deleteItemAsync(key);
}
async setItem(key: string, value: string) {
const encrypted = await this._encrypt(key, value);
await AsyncStorage.setItem(key, encrypted);
}
}
export const supabase = createClient<Database>(
supabaseUrl,
process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY,
{
auth: {
storage: new LargeSecureStore(),
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
}
)
Plus this one for handling foreground / background handling but even with or without no difference:
AppState.addEventListener('change', (state) => {
if (state === 'active') {
supabase.auth.startAutoRefresh()
} else {
supabase.auth.stopAutoRefresh()
}
})
Majorly I dont see any events or tries of refreshing the token.
Moreover default 1 hour of course stays longer logged in but setting 50, 60 or 120 seconds mostly logs me out after good 20 seconds. Can someone official have a look into this as it seems to be a big UX blocker?
I'm getting the same thing. To reproduce more easily, I set the token to 10 seconds. I'm running with supabase/ssr server-only with SvelteKit, a single supabase client in locals that is used throughout the request:
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, {
auth: { debug: true },
cookies: {
get: (key) => {
const value = event.cookies.get(key);
// debug('cookies get', { key, value });
return value;
},
set: (key, value, options) => {
// debug('cookies set', { key, value, options });
event.cookies.set(key, value, { ...options, path: options.path ?? '/' });
},
remove: (key, options) => {
// debug('cookies remove', { key, options });
event.cookies.delete(key, { ...options, path: options.path ?? '/' });
}
}
});
event.locals.safeGetSession = async () => {
const {
data: { session }
} = await event.locals.supabase.auth.getSession();
if (!session) {
debug('No session found');
return { session: null, user: null };
}
const {
data: { user },
error
} = await event.locals.supabase.auth.getUser();
if (error) {
debug('Error getting user: ', error);
// JWT validation has failed
return { session: null, user: null };
}
return { session, user };
};
const { session, user } = await event.locals.safeGetSession();
event.locals.session = session ?? undefined;
event.locals.user = user ?? undefined;
[ ... ]
Here is the traceback:
app:hooks:supabase Error getting user: AuthApiError: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired
at handleError (/home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/lib/fetch.js:63:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async _handleRequest (/home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/lib/fetch.js:108:9)
at async _request (/home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/lib/fetch.js:89:18)
at async /home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/GoTrueClient.js:874:24
at async SupabaseAuthClient._useSession (/home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/GoTrueClient.js:774:20)
at async SupabaseAuthClient._getUser (/home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/GoTrueClient.js:864:20)
at async /home/xl0/work/projects/llms/assistant/node_modules/@supabase/auth-js/dist/main/GoTrueClient.js:851:20 {
__isAuthError: true,
status: 403,
code: 'bad_jwt'
} +8m
I turned on auth: {debug: true}, will see if I can catch another one.
Ok, I think I know what's going on, at least in my case. There is a race condition between the check for the session expiration and when the session is used to get the user: node_modules/@supabase/auth-js/src/GoTrueClient.ts:
const hasExpired = currentSession.expires_at
? currentSession.expires_at <= Date.now() / 1000
: false
this._debug(
'#__loadSession()',
`session has${hasExpired ? '' : ' not'} expired`,
'expires_at',
currentSession.expires_at
)
if (!hasExpired) {
[ return the session ]
[ refresh the session ]
If the session is expiring in the new milliseconds, this causes the exception. I think an easy workaround would be to add an arbitrary or configurable offset to the session expiration check and refresh a session that expires very soon.
@kiwicopple @awalias
Bug report
Describe the bug
After initialising supabase client with
and setting the JWT expiry to 60 (seconds) on the supabase dashboard, the token does not refresh after 60 seconds have elapsed. Oddly enough, setting the JWT expiry to anything less than 60 triggers the token refresh but it constantly updates without waiting for expiry
To Reproduce
Steps to reproduce the behavior, please provide code snippets or a repository:
Expected behavior
The token should refresh after the expiry time set on the supabase dashboard
System information