Skip to content

User id on the client is different from the one generated on the server #458

@AnthonyDM-Dev

Description

@AnthonyDM-Dev

Hi everyone,

I am using nuxt-auth-utils in my project and everything is working fine on my local machine.

I then deployed my project on a production server (ubuntu 24.04 in a docker container using node:22-alpine) and I came across the following issue:

on my production site I cannot login because the session api received on the client is different from the one generated on the server side.

These are the informations generated on the server side when I login
Image
Id is cd9e1eea-bd24-43bb-b89a-572bdcc31927.

And this is the id the I receive on the client. "Risposta" is the "Response" tab:
Image
Id is 1b21e290-0d3d-49ae-9e52-63c7af27beb2.

The repository on my production site is identical to the one i have locally.
Same thing for the nodejs version used (v22.11.0).
I am using nuxt v3.17.3 and nuxt-auth-utils v0.5.20.

The authentication flow I implemented seems pretty straightforward to me and is the following:

Login.vue

<template>
    <v-card :title="$t('loginPage')" class="text-center">
        <form @submit.prevent="handleSubmit" class="pa-3 d-flex flex-column" style="width:300px">
            <v-text-field
                label="Email"
                required
                type="email"
                density="compact"
                v-model="credentials.email"
                :disabled="loginWaiting"
            />
            <v-text-field
                label="Password"
                type="password"
                required
                density="compact"
                v-model="credentials.password"
                :disabled="loginWaiting"
            />
            <v-btn type="submit" :loading="loginWaiting" :disabled="loginWaiting">
                {{$t('login')}}
            </v-btn>
            <p>{{ $t('or') }}</p>
            <NuxtLink :to="ClientRoute.SIGNUP">
            <v-btn class="w-100" :disabled="loginWaiting">
                {{$t('signup')}}
            </v-btn>
            </NuxtLink>
        </form>
        <v-snackbar
            v-model="snackbarProps.isOpen"
            :timeout="snackbarProps.timeout"
            :color="snackbarProps.color"
            :location="snackbarProps.location"
        >
            {{ $t(snackbarProps.text||'') }}

            <template v-slot:actions>
            <v-btn
                @click="snackbarProps.isOpen = false"
            >
                {{ $t('close') }}
            </v-btn>
            </template>
        </v-snackbar>
    </v-card>
</template>
<script setup lang="ts">
import { ClientRoute } from '~/types/api/Routes';
import type { NuxtAuthCredentials } from '~/types/composables/useAuthComp';

const {login} = useAuthComp();
const {
    addLoader,
    removeLoader,
    getLoaderStatus,
} = useEntityLoadersComp();
const {setSnackbar,snackbarProps} = useSnackbarComp();
const credentials:NuxtAuthCredentials = reactive({
  email: '',
  password: '',
});
const loginWaiting = computed(() => getLoaderStatus('login'));

const handleSubmit = async () => {
    addLoader('login');
    const response = await login(credentials);
    removeLoader('login');
    setSnackbar({
        isOpen:true,
        timeout:3000,
        location:"bottom center",
        text:response?.statusMessage||'noContent',
        color:(response as any)?.status === 204 ? 'success':'info',
    });
};
const login = async (credentials:NuxtAuthCredentials) => {
        return await $fetch(SsrRoute.LOGIN_API, {
            method: 'POST',
            body: credentials
        })
        .then(async (response) => {
            // Refresh the session on client-side and redirect to the dashboard
            await refreshSession();
            await navigateTo(ClientRoute.DASHBOARD)
        })
        .catch((error) => {
            return error?.data as OFetchErrorData;
        })
    }

definePageMeta({
    layout:'auth',
    middleware:['auth']
})
</script>

The $fetch then call my login api on server:

index.post.ts:

import { z } from 'zod'
import useMongoDBComp from '~/composables/db/useMongoDbComp';
import { UserDbColl } from '~/types/db/collections/User';
import { DbCollectionEnum } from '~/types/db/CRUD';

const bodySchema = z.object({
  email: z.email(),
  password: z.string().min(8),  
})

export default defineEventHandler(async (event) => {
  const {executeQuery,dbFind} = useMongoDBComp();

  const { email, password } = await readValidatedBody(event, bodySchema.parse);
  const user = await executeQuery(() => dbFind(DbCollectionEnum.USERS,{
      query: {email},
      projection:{email:1,password:1},
      config:{limit:1},
  })) as UserDbColl;
  
  console.log('USER LOGGED: ', user);

  if (user && await verifyPassword(user?.password||'',password)) {
    await setUserSession(event, {
      user: {
        email: user.email,
      },
      secure: {
        userId:user._id.toString(),
      },
      loggedInAt: new Date(),
    })
    const session = await getUserSession(event);
    console.log('USER SET. USER SESSION: ', session);

    return {};
  }
  throw createError({
    statusCode: 401,
    statusMessage: 'badCredentials',
  })
})

I am trying to debug it but I really do not get it.
Can you please help me understand what is going on when the session api is called?

Thank you in advance :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions