diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index 114248aa..f0bdbd2c 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -7,7 +7,7 @@ import { getRequestURLWN } from '../../utils/callWithNuxt' import { useAuthState } from './useAuthState' // @ts-expect-error - #auth not defined import type { SessionData } from '#auth' -import { useNuxtApp, useRuntimeConfig, nextTick, navigateTo } from '#imports' +import { useCookie, useNuxtApp, useRuntimeConfig, nextTick, navigateTo } from '#imports' type Credentials = { username?: string, email?: string, password?: string } & Record @@ -82,16 +82,28 @@ const getSession: GetSessionFunc = async (getSessionO const headers = new Headers(token.value ? { [config.token.headerName]: token.value } as HeadersInit : undefined) + const sessionCookie = useCookie('auth:sessionCookie', { + default: () => null, + maxAge: config.token.maxAgeInSeconds, + sameSite: config.token.sameSiteAttribute + }) + loading.value = true try { data.value = await _fetch(nuxt, path, { method, headers }) + // Store the session data as a cookie + lastRefreshedAt.value = new Date() + sessionCookie.value = { + lastRefreshedAt: lastRefreshedAt.value, + data: data.value + } } catch { // Clear all data: Request failed so we must not be authenticated data.value = null rawToken.value = null + sessionCookie.value = null } loading.value = false - lastRefreshedAt.value = new Date() const { required = false, callbackUrl, onUnauthenticated, external } = getSessionOptions ?? {} if (required && data.value === null) { diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 9c27a8c9..c3055ff3 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -1,10 +1,12 @@ import { getHeader } from 'h3' import authMiddleware from './middleware/auth' -import { addRouteMiddleware, defineNuxtPlugin, useRuntimeConfig, useAuth, useAuthState } from '#imports' +import { useTypedBackendConfig } from './helpers' +import type { SessionCookie } from './types' +import { addRouteMiddleware, defineNuxtPlugin, useRuntimeConfig, useAuth, useAuthState, useCookie } from '#imports' export default defineNuxtPlugin(async (nuxtApp) => { // 1. Initialize authentication state, potentially fetch current session - const { data, lastRefreshedAt } = useAuthState() + const { data, lastRefreshedAt, rawToken, loading } = useAuthState() const { getSession } = useAuth() // use runtimeConfig @@ -19,6 +21,27 @@ export default defineNuxtPlugin(async (nuxtApp) => { // Only fetch session if it was not yet initialized server-side if (typeof data.value === 'undefined' && !nitroPrerender) { + // Restore the session data from the cookie + const config = useTypedBackendConfig(useRuntimeConfig(), 'local') + const sessionCookie = useCookie('auth:sessionCookie') + const cookieToken = useCookie(config.token.cookieName) + if (sessionCookie.value && !rawToken.value && cookieToken.value) { + 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 + } + } + + if (!data.value) { + await getSession() + } await getSession() } diff --git a/src/runtime/types.ts b/src/runtime/types.ts index ce088b04..ba6b558a 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -476,6 +476,10 @@ export interface ModuleOptionsNormalized extends ModuleOptions { fullBaseUrl: string } } +export interface SessionCookie { + lastRefreshedAt?: SessionLastRefreshedAt + data?: SessionDataObject +} // Augment types declare module 'nuxt/schema' {