The signedIn
state is shown as false
on the server-side after a page reload, even though the session cookie exists and the client correctly shows it as true
. When I first sign in, I can see the cookie is added in the browser, and also I see it in the terminal and signedIn
is set to true
. After I reload the page, I still can see the cookie in both terminal and the browser, but now I also see:
*ssr* signedIn: false
signedIn: true
which probably indicates that signedIn
state on server does not match state on client after page reload, although the response is successful and the cookie persists. Also, after page reload I can see multiple hydration issues occur in the console and my header ‘sign out’ button and ‘profile’ link are messed up, because now ‘sign in’ link appeared as well.
Video of the issue: https://www.veed.io/view/4a6216e4-6316-4cd3-8829-08034de3a1fe?panel=share. Here I’m signed in and I reload the page, the issue occurs, I can see both profile, sign out and sign in in the DOM, and then I click sign out.
Function in the composable:
const checkSession = async () => {
const { apiBase } = useRuntimeConfig().public;
try {
const res = await $fetch<{ signedIn: boolean }>(
`${apiBase}/check-session`
);
state.signedIn = res.signedIn;
console.log('signedIn: ', res.signedIn);
} catch (err) {
console.error('Error checking session: ', err);
}
};
check-session.get.ts:
export default defineEventHandler(async event => {
const sessionCookie = getCookie(event, 'session');
if (sessionCookie) {
console.log('cookie (server): ', sessionCookie);
return { signedIn: true };
}
return { signedIn: false };
});
Header template:
<div v-if="!signedIn">
<NuxtLink
class="flex items-center gap-2"
to="/sign-in">
<span>Sign In</span>
</NuxtLink>
</div>
<div
class="flex items-center gap-10 lg-max:gap-4"
v-else>
<NuxtLink
class="flex items-center gap-2"
to="/profile">
<span>Profile</span>
</NuxtLink>
<button
class="flex items-center gap-2"
@click="handleSignOut">
<span>Sign Out</span>
</button>
</div>
I suppose the issue might be related to the Nitro as it is in between the Vue front and API, but I’m not sure.
Looking for a possible solution. Let me know if you need more details.