Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The session doesn't last the maxAge value - logged out randomly #325

Open
luminous8 opened this issue Jan 17, 2025 · 1 comment
Open

The session doesn't last the maxAge value - logged out randomly #325

luminous8 opened this issue Jan 17, 2025 · 1 comment
Labels
question Further information is requested

Comments

@luminous8
Copy link

luminous8 commented Jan 17, 2025

Hey

I'm not 100% if the issue if the issue is on my end or not (and i'm having hard time to figuring it)
I can successfully log in with the module but me (and my users are randomly logged out)
It was working fine until a couple of week and i'm not able to identify the source of the issue and the pattern that triggers this

in my /server/plugin/session.ts

export default defineNitroPlugin(async (nitroApp) => {
	console.log('session plugin', { sessionHooks });
	sessionHooks.hook('fetch', async (session, event) => {
		try {
			console.log('1. Getting user session', { session, event });
			console.log('event', event);
			// const session = (await getUserSession(event)) || {};
			// console.log('2. User session retrieved:', { session });

			if (!session?.token) {
				console.log('3. No token found in session');
				await clearUserSession(event);
			}

			// console.log('4. Verifying existing token');
			// const isValid = await verifyToken(session?.token);
			// console.log('5. Token validation result:', { isValid });

			// if (!isValid) {
			// 	console.log('6. Token is invalid, clearing session');
			// 	return await clearUserSession(event);
			// }

			console.log('7. Getting runtime config');
			const runtimeConfig = useRuntimeConfig();

			console.log('8. Refreshing token');
			const { token } =
				(await $fetch(
					`${runtimeConfig.public.DOMAIN_BACK_URL}/v2/auth/refresh-token`,
					{
						method: 'POST',
						headers: {
							...(session?.token && {
								authorization: session?.token,
							}),
						},
					},
				)) || {};
			console.log('9. Token refresh result:', { hasToken: !!token });

			if (!token) {
				console.log('10. No token received from refresh, redirecting to auth');
				return sendRedirect(event, '/auth');
			}

			console.log('11. Verifying refreshed token');
			const isTokenValid = await verifyToken(token);
			console.log('12. Refreshed token validation result:', { isTokenValid });

			if (!isTokenValid) {
				console.log('13. Refreshed token is invalid, redirecting to auth');
				return sendRedirect(event, '/auth');
			}

			console.log('14. Getting user from token');
			const user = await getUserFromToken(token);
			console.log('15. User from token:', { hasUser: !!user });

			if (user) {
				console.log('16. Setting new user session');
				await setUserSession(event, {
					...session,
					user: user,
					token: token,
				});
				console.log('17. User session updated successfully');
			} else {
				console.log('18. No user found, clearing session');
				// await clearUserSession(event);
				throw createError({
					statusCode: 401,
					statusMessage: 'Session expired',
				});
			}
		} catch (error) {
			console.log('19. Error in session hook:', { error });
			// await clearUserSession(event);
			throw createError({
				statusCode: 401,
				statusMessage: 'Session expired',
			});
		}

		console.log('20. Setting extended session properties');
		session.extended = {
			fromHooks: true,
			last_refresh: new Date(),
		};
		console.log('21. Session hook completed');
	});
});

my nuxt.config.ts looks like this

runtimeConfig: { session: { maxAge: 60 * 60 * 24 * 365, // 365 days }, oauth: { google: { clientId: process.env.GOOGLE_OAUTH_CLIENT_ID, clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET, }, }, routeRules: { // some of my route are cached '/': { swr: true, cache: { maxAge: 3600, swr: true, } }, // 60 minutes '/auth': { swr: 86400 }, } ...
my header.vue using AuthState
`...<div
class="flex basis-full flex-row items-center justify-end gap-2 lg:flex"

<AuthState>
	<template #default="{ loggedIn, user }">
		<div class="hidden flex-row gap-0.5 md:flex">
			<NuxtLink
				v-if="!loggedIn"
				:to="{ name: 'auth' }"
				class="flex-none"
			>
				<UiButton label="Sign in" btn-style="ghost" />
			</NuxtLink>
			<NuxtLink
				v-if="!loggedIn"
				:to="{ name: 'auth' }"
				class="flex-none"
			>
				<UiButton label="Join now" btn-style="ghost" />
			</NuxtLink>
		</div>
		<NuxtLink
			:to="{ name: 'myroute' }"
			v-if="!loggedIn || !user?.has_access"
			class="hidden md:block"
		>
			<UiButton class="flex flex-row gap-1.5"
				><div class="text-white">❖</div>
				GO to route
			</UiButton></NuxtLink
		>
		<ul class="flex flex-none items-center gap-2" v-if="user">
			<NuxtLink
				:to="{ name: route.routeName }"
				v-for="route in secondaryRoutes"
			>
				{{ route.title }}
			</NuxtLink>
		</ul>
		<div
			class="group relative"
			v-if="loggedIn"
			@click="togglePersonalDropdown"
		>
			<div
				class="relative flex h-9 cursor-pointer items-center gap-2 rounded border p-1.5 pr-2"
			>
				<div
					:class="[
						{
							'!bg-brand !text-base !text-white': user?.has_access,
						},
					]"
				>
					<template v-if="user?.has_access">❖</template>
					<template v-else>
						{{
							(
								user?.firstname?.charAt(0) || user?.email?.charAt(0)
							)?.toUpperCase()
						}}
					</template>
				</div>
				<span>{{
					user?.firstname || user?.lastname || user?.email
				}}</span>
			</div>
			<UiDropdown
				class="absolute right-0 top-8 w-full w-max origin-top-left flex-col gap-0.5 p-1 md:group-hover:flex"
				:class="{
					hidden: !isPersonalDropdownVisible,
					flex: isPersonalDropdownVisible,
				}"
			>
				...
					<div
						v-if="loggedIn"
						class="flex flex-none cursor-pointer flex-row rounded p-2 px-3 py-1 hover:bg-gray-50 hover:text-brand"
						@click="logout"
					>
						Sign out
					</div>
				</div>
			</UiDropdown>
		</div>
		<UiButton
			btn-style="ghost"
			class="mx-0 flex gap-2 px-0"
			@click="showModal('mainMenu')"
		>
			<Icon
				name="burger"
				size="16"
				class="icon-cursor text-gray-600"
			/>
		</UiButton>
	</template>
	<template #placeholder>
		<UiButton
			btn-style="ghost"
			class="mx-0 flex gap-2 px-0"
			@click="showModal('mainMenu')"
		>
			<Icon
				name="burger"
				size="16"
				class="icon-cursor text-gray-600"
			/>
		</UiButton>
	</template>
</AuthState>
...`

not that i'm not using clearUserSession else, and only use clear() in the header for the user to logout

The nuxt-session cookie expires in 6 months, not 1 year (as set in nuxt config)
Image


  • Do you see any issue in my code?
  • Any tips to debug this kind of issues?

Thanks for the help 🙏

@atinux atinux added the question Further information is requested label Jan 21, 2025
@norjamille-kasan
Copy link

i'm facing the same issue. any update on this ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants