From 6dd86b2fb8035bc47fa0fd9ef71c614e3c099532 Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Thu, 14 Mar 2024 19:13:57 +0530 Subject: [PATCH 01/12] set and reload data, rawToken from cookie --- src/runtime/composables/local/useAuth.ts | 16 +++++++++++++-- src/runtime/plugin.ts | 26 ++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index 114248aa..6aed7df9 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..c818fd62 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -1,10 +1,10 @@ import { getHeader } from 'h3' import authMiddleware from './middleware/auth' -import { addRouteMiddleware, defineNuxtPlugin, useRuntimeConfig, useAuth, useAuthState } from '#imports' +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 +19,28 @@ 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 sessionCookie = useCookie("auth:sessionCookie"); + const cookieToken = useCookie( + runtimeConfig.provider.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() } From 8a361181fc3282322633584afa8a6d28345642c4 Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Thu, 14 Mar 2024 19:41:02 +0530 Subject: [PATCH 02/12] fix lint --- src/runtime/composables/local/useAuth.ts | 14 +++++++------- src/runtime/plugin.ts | 20 ++++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index 6aed7df9..f0bdbd2c 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -82,26 +82,26 @@ const getSession: GetSessionFunc = async (getSessionO const headers = new Headers(token.value ? { [config.token.headerName]: token.value } as HeadersInit : undefined) - const sessionCookie = useCookie("auth:sessionCookie", { + const sessionCookie = useCookie('auth:sessionCookie', { default: () => null, maxAge: config.token.maxAgeInSeconds, - sameSite: config.token.sameSiteAttribute, - }); + 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(); + lastRefreshedAt.value = new Date() sessionCookie.value = { lastRefreshedAt: lastRefreshedAt.value, - data: data.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; + sessionCookie.value = null } loading.value = false diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index c818fd62..2dc718c8 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -20,26 +20,26 @@ 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 sessionCookie = useCookie("auth:sessionCookie"); + const sessionCookie = useCookie('auth:sessionCookie') const cookieToken = useCookie( runtimeConfig.provider.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; + 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); + console.error('Failed to parse session data from cookie:', error) } finally { - loading.value = false; + loading.value = false } } if (!data.value) { - await getSession(); + await getSession() } await getSession() } From 9b4b8b12f3149cc1615e42bdfe10499730e0ff83 Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Thu, 14 Mar 2024 20:27:00 +0530 Subject: [PATCH 03/12] fix typecheck --- src/runtime/plugin.ts | 9 +++++---- src/runtime/types.ts | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 2dc718c8..c3055ff3 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -1,5 +1,7 @@ import { getHeader } from 'h3' import authMiddleware from './middleware/auth' +import { useTypedBackendConfig } from './helpers' +import type { SessionCookie } from './types' import { addRouteMiddleware, defineNuxtPlugin, useRuntimeConfig, useAuth, useAuthState, useCookie } from '#imports' export default defineNuxtPlugin(async (nuxtApp) => { @@ -20,10 +22,9 @@ 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 sessionCookie = useCookie('auth:sessionCookie') - const cookieToken = useCookie( - runtimeConfig.provider.token.cookieName - ) + 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 diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 094c446e..e49493cb 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -461,6 +461,10 @@ export interface ModuleOptionsNormalized extends ModuleOptions { fullBaseUrl: string } } +export interface SessionCookie { + lastRefreshedAt?: SessionLastRefreshedAt + data?: SessionDataObject +} // Augment types declare module 'nuxt/schema' { From d37195032be35116cf5c3304fd68b698fda65fef Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Thu, 14 Mar 2024 19:13:57 +0530 Subject: [PATCH 04/12] set and reload data, rawToken from cookie set and reload data, rawToken from cookie fix lint fix typecheck --- src/runtime/composables/local/useAuth.ts | 12 +++++++++- src/runtime/plugin.ts | 28 +++++++++++++++++++++--- src/runtime/types.ts | 11 ++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index e2a60e3a..58d7d2b4 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -9,7 +9,7 @@ import { formatToken } from '../../utils/local' 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 @@ -91,12 +91,21 @@ const getSession: GetSessionFunc = async (getSessionO if (getSessionConfig) { const headers = new Headers(token ? { [config.token.headerName]: token } as HeadersInit : undefined) const { path, method } = getSessionConfig + const sessionCookie = useCookie('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) { console.error(`Session: unable to extract session, ${err.message}`) @@ -105,6 +114,7 @@ const getSession: GetSessionFunc = async (getSessionO // 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() diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 5fd14eca..8263f405 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -1,11 +1,13 @@ import { getHeader } from 'h3' import authMiddleware from './middleware/auth' import { getNitroRouteRules } from './utils/kit' -import { addRouteMiddleware, defineNuxtPlugin, useRuntimeConfig, useAuth, useAuthState, _refreshHandler } from '#imports' +import { useTypedBackendConfig } from './helpers' +import type { SessionCookie } from './types' +import { addRouteMiddleware, defineNuxtPlugin, useRuntimeConfig, useAuth, useAuthState, useCookie, _refreshHandler } from '#imports' export default defineNuxtPlugin(async (nuxtApp) => { // 1. Initialize authentication state, potentially fetch current session - const { data, lastRefreshedAt, loading } = useAuthState() + const { data, lastRefreshedAt, rawToken, loading } = useAuthState() const { getSession } = useAuth() // use runtimeConfig @@ -31,7 +33,27 @@ export default defineNuxtPlugin(async (nuxtApp) => { // Only fetch session if it was not yet initialized server-side if (typeof data.value === 'undefined' && !nitroPrerender && !disableServerSideAuth) { - await getSession() + // Restore the session data from the cookie if it exists + 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() + } } // 2. Setup session maintanence, e.g., auto refreshing or refreshing on foux diff --git a/src/runtime/types.ts b/src/runtime/types.ts index 05313d8e..15b616de 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -573,3 +573,14 @@ export interface ModuleOptionsNormalized extends ModuleOptions { fullBaseUrl: string } } +export interface SessionCookie { + lastRefreshedAt?: SessionLastRefreshedAt + data?: SessionDataObject +} + +// Augment types +declare module 'nuxt/schema' { + interface PublicRuntimeConfig { + auth: ModuleOptionsNormalized + } +} From 5780a4517b453d8dacfe46024555e7daa6fc25ee Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Fri, 5 Jul 2024 18:10:53 +0530 Subject: [PATCH 05/12] fix undefined sessionCookie case --- src/runtime/plugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 8263f405..421ff0db 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -36,8 +36,8 @@ export default defineNuxtPlugin(async (nuxtApp) => { // Restore the session data from the cookie if it exists const config = useTypedBackendConfig(useRuntimeConfig(), 'local') const sessionCookie = useCookie('auth:sessionCookie') - const cookieToken = useCookie(config.token.cookieName) - if (sessionCookie.value && !rawToken.value && cookieToken.value) { + const cookieToken = useCookie(config.token?.cookieName) + if (sessionCookie?.value && !rawToken?.value && cookieToken?.value) { try { loading.value = true const sessionData = sessionCookie.value From d8f04612c338ac69e346531b96f526c1ee521885 Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Sat, 6 Jul 2024 23:32:14 +0530 Subject: [PATCH 06/12] fix lint --- src/runtime/composables/local/useAuth.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index 841aeea7..f03acf3b 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -111,7 +111,6 @@ const getSession: GetSessionFunc = async (getSessionO console.error(`Session: unable to extract session, ${err.message}`) } - // Clear all data: Request failed so we must not be authenticated data.value = null rawToken.value = null From d81404884809ed4a191215c031dbc67f85e65f22 Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Sat, 6 Jul 2024 23:40:10 +0530 Subject: [PATCH 07/12] fix undefined cases --- src/runtime/plugin.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 74cae78e..27a34d9e 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -32,12 +32,12 @@ export default defineNuxtPlugin(async (nuxtApp) => { } // Only fetch session if it was not yet initialized server-side - if (typeof data.value === 'undefined' && !nitroPrerender) { + if (typeof data.value === 'undefined' && !nitroPrerender && !disableServerSideAuth) { // 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) { + const cookieToken = useCookie(config.token?.cookieName) + if (sessionCookie?.value && !rawToken?.value && cookieToken?.value) { try { loading.value = true const sessionData = sessionCookie.value From b0ad9845bf16939844891d6f7749c0861f38588f Mon Sep 17 00:00:00 2001 From: Zoey Date: Wed, 18 Sep 2024 19:19:49 +0200 Subject: [PATCH 08/12] fix: linting in useAuth --- src/runtime/composables/local/useAuth.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/runtime/composables/local/useAuth.ts b/src/runtime/composables/local/useAuth.ts index aae5a936..845cc3b1 100644 --- a/src/runtime/composables/local/useAuth.ts +++ b/src/runtime/composables/local/useAuth.ts @@ -123,7 +123,7 @@ async function getSession(getSessionOptions?: GetSessionOptions): Promise('auth:sessionCookie', { + const sessionCookie = useCookie('auth:sessionCookie', { default: () => null, maxAge: config.token.maxAgeInSeconds, sameSite: config.token.sameSiteAttribute @@ -139,7 +139,8 @@ async function getSession(getSessionOptions?: GetSessionOptions): Promise Date: Wed, 18 Sep 2024 19:20:23 +0200 Subject: [PATCH 09/12] fix: lint in plugin --- src/runtime/plugin.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 20cb7729..6ffba403 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -44,9 +44,11 @@ export default defineNuxtPlugin(async (nuxtApp) => { lastRefreshedAt.value = sessionData?.lastRefreshedAt data.value = sessionData?.data rawToken.value = cookieToken.value - } catch (error) { + } + catch (error) { console.error('Failed to parse session data from cookie:', error) - } finally { + } + finally { loading.value = false } } From 907ff2eaa38dc2bcfd174da8df8eaf45a7abc0ca Mon Sep 17 00:00:00 2001 From: Zoey Date: Wed, 18 Sep 2024 19:21:29 +0200 Subject: [PATCH 10/12] fix: trailing spaces --- src/runtime/plugin.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 6ffba403..02c72fd3 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -44,10 +44,10 @@ export default defineNuxtPlugin(async (nuxtApp) => { 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 } From f812357a330d6b3dc03589c6451f30b700c09ea8 Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Thu, 19 Sep 2024 17:12:34 +0530 Subject: [PATCH 11/12] organize code --- src/runtime/plugin.ts | 64 +++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index 02c72fd3..f86ce68a 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -1,8 +1,8 @@ import { getHeader } from 'h3' import authMiddleware from './middleware/auth' import { getNitroRouteRules } from './utils/kit' -import { useTypedBackendConfig } from './helpers' -import type { SessionCookie } from './types' +import type { ProviderLocal, SessionCookie } from './types' +import type { CookieRef } from '#app' import { _refreshHandler, addRouteMiddleware, defineNuxtPlugin, useAuth, useAuthState, useCookie, useRuntimeConfig } from '#imports' export default defineNuxtPlugin(async (nuxtApp) => { @@ -32,25 +32,15 @@ export default defineNuxtPlugin(async (nuxtApp) => { } // Only fetch session if it was not yet initialized server-side - if (typeof data.value === 'undefined' && !nitroPrerender && !disableServerSideAuth) { - // 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 ( + typeof data.value === 'undefined' + && !nitroPrerender + && !disableServerSideAuth + ) { + const config = runtimeConfig.provider as ProviderLocal + + if (config.type === 'local') { + await handleLocalAuth(config) } if (!data.value) { @@ -58,6 +48,38 @@ export default defineNuxtPlugin(async (nuxtApp) => { } } + 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 + } + } + // 2. Setup session maintanence, e.g., auto refreshing or refreshing on foux nuxtApp.hook('app:mounted', () => { _refreshHandler.init() From 86feff34929e399375698a05879b3edc38a4a9df Mon Sep 17 00:00:00 2001 From: Vijayabhaskar J Date: Thu, 19 Sep 2024 17:26:41 +0530 Subject: [PATCH 12/12] fix typo --- src/runtime/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index f86ce68a..a51c1447 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -40,7 +40,7 @@ export default defineNuxtPlugin(async (nuxtApp) => { const config = runtimeConfig.provider as ProviderLocal if (config.type === 'local') { - await handleLocalAuth(config) + handleLocalAuth(config) } if (!data.value) {