diff --git a/packages/nc-gui-v2/composables/useGlobalState.ts b/packages/nc-gui-v2/composables/useGlobalState.ts index ce837abf64..19ac102e86 100644 --- a/packages/nc-gui-v2/composables/useGlobalState.ts +++ b/packages/nc-gui-v2/composables/useGlobalState.ts @@ -1,7 +1,7 @@ import { usePreferredDark, usePreferredLanguages, useStorage } from '@vueuse/core' import { useJwt } from '@vueuse/integrations/useJwt' import type { JwtPayload } from 'jwt-decode' -import { computed, toRefs } from '#build/imports' +import { computed, toRefs, useNuxtApp, watch } from '#imports' import type { Actions, Getters, GlobalState, State, User } from '~/lib/types' const storageKey = 'nocodb-gui-v2' @@ -28,6 +28,8 @@ export const useGlobalState = (): GlobalState => { /** get the preferred dark mode setting, according to browser settings */ const darkMode = $(usePreferredDark()) + const { $api } = useNuxtApp() + /** * Split language string and only use the first part, e.g. 'en-GB' -> 'en' * todo: use the full language string, e.g. 'en-GB-x-whatever' -> 'en-GB' and confirm if language exists against our list of languages (hint: vite plugin i18n provides a list) @@ -77,5 +79,34 @@ export const useGlobalState = (): GlobalState => { } } + /** manually try to refresh token */ + const refreshToken = async () => { + $api.instance + .post('/auth/refresh-token', null, { + withCredentials: true, + }) + .then((response) => { + if (response.data?.token) { + signIn(response.data.token) + } + }) + .catch((err) => { + console.error(err) + + signOut() + }) + } + + /** try to refresh token before expiry (5 min before expiry) */ + watch( + () => !!(payload && payload.exp && payload.exp > Date.now() / 1000 - 5 * 60), + (expiring) => { + if (payload && expiring) { + refreshToken() + } + }, + { immediate: true }, + ) + return { ...toRefs(storage), signedIn, signOut, signIn } } diff --git a/packages/nc-gui-v2/plugins/api.ts b/packages/nc-gui-v2/plugins/api.ts index 06522ed3e6..16b352fbca 100644 --- a/packages/nc-gui-v2/plugins/api.ts +++ b/packages/nc-gui-v2/plugins/api.ts @@ -43,18 +43,14 @@ function addAxiosInterceptors(api: Api, app: { $state: GlobalState }) { // Return any error which is not due to authentication back to the calling service if (!error.response || error.response.status !== 401) { - return new Promise((resolve, reject) => { - reject(error) - }) + return error } // Logout user if token refresh didn't work or user is disabled if (error.config.url === '/auth/refresh-token') { app.$state.signOut() - return new Promise((resolve, reject) => { - reject(error) - }) + return error } // Try request again with new token @@ -66,7 +62,7 @@ function addAxiosInterceptors(api: Api, app: { $state: GlobalState }) { // New request with new token const config = error.config config.headers['xc-auth'] = token.data.token - if (app.$state.token.value) app.$state.signIn(token.data.token) + app.$state.signIn(token.data.token) return new Promise((resolve, reject) => { api.instance