diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index c122262c..cc13f401 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -10,7 +10,7 @@ import { type UseAuthStateReturn, useAuthState } from './useAuthState' import { callWithNuxt } from '#app/nuxt' // @ts-expect-error - #auth not defined import type { SessionData } from '#auth' -import { navigateTo, nextTick, useNuxtApp, useRoute, useRuntimeConfig } from '#imports' +import { navigateTo, nextTick, useCookie, useNuxtApp, useRoute, useRuntimeConfig } from '#imports' type Credentials = { username?: string, email?: string, password?: string } & Record @@ -132,11 +132,22 @@ async function getSession(getSessionOptions?: GetSessionOptions): Promise('auth:sessionCookie', { + default: () => null, + maxAge: config.token.maxAgeInSeconds, + sameSite: config.token.sameSiteAttribute + }) + loading.value = true try { const result = await _fetch(nuxt, path, { method, headers }) const { dataResponsePointer: sessionDataResponsePointer } = config.session data.value = jsonPointerGet(result, sessionDataResponsePointer) + + sessionCookie.value = { + lastRefreshedAt: lastRefreshedAt.value, + data: data.value + } } catch (err) { if (!data.value && err instanceof Error) { @@ -146,6 +157,7 @@ async function getSession(getSessionOptions?: GetSessionOptions): Promise { // 1. Initialize authentication state, potentially fetch current session - const { data, lastRefreshedAt, loading } = useAuthState() + const { data, lastRefreshedAt, rawToken, loading } = useAuthState() const { getSession } = useAuth() // use runtimeConfig @@ -48,14 +50,52 @@ export default defineNuxtPlugin(async (nuxtApp) => { && !(isErrorUrl && requireAuthOnErrorPage) if (shouldFetchSession) { - try { - await getSession() + if (runtimeConfig.provider.type === 'local') { + handleLocalAuth(runtimeConfig.provider) } - catch (e) { - // Do not throw the configuration error as it can lead to infinite recursion - if (!(e instanceof FetchConfigurationError)) { - throw e + + if (!data.value) { + try { + await getSession() } + catch (e) { + // Do not throw the configuration error as it can lead to infinite recursion + if (!(e instanceof FetchConfigurationError)) { + throw e + } + } + } + } + + function handleLocalAuth(config: ProviderLocal): void { + const sessionCookie = useCookie( + 'auth:sessionCookie' + ) + const cookieToken = useCookie( + config.token?.cookieName ?? 'auth.token' + ) + + if (sessionCookie?.value && !rawToken?.value && cookieToken?.value) { + restoreSessionFromCookie(sessionCookie, cookieToken) + } + } + + function restoreSessionFromCookie( + sessionCookie: CookieRef, + cookieToken: CookieRef + ): void { + try { + loading.value = true + const sessionData = sessionCookie.value + lastRefreshedAt.value = sessionData?.lastRefreshedAt + data.value = sessionData?.data + rawToken.value = cookieToken.value + } + catch (error) { + console.error('Failed to parse session data from cookie:', error) + } + finally { + loading.value = false } } diff --git a/src/runtime/types.ts b/src/runtime/types.ts index e94c1707..72ce770c 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -629,3 +629,14 @@ export interface ModuleOptionsNormalized extends ModuleOptions { globalAppMiddleware: NonNullable originEnvKey: string } +export interface SessionCookie { + lastRefreshedAt?: SessionLastRefreshedAt + data?: SessionDataObject +} + +// Augment types +declare module 'nuxt/schema' { + interface PublicRuntimeConfig { + auth: ModuleOptionsNormalized + } +}