N
Nuxtβ€’11h ago
Krd8ssb

data not persisting between updating store value and a navigateTo redirect

I'm working on my first nuxt app and am running into an issue with pinia updating properly before I use navigateTo for a redirect. Use case: I have my app receiving a callback as part of the auth flow from WorkOS (My app has SSR enabled and persisted state is using cookies). Once a user authenticates with their google account (or email/password) via WorkOS, it sends the auth code to my app /callback?code={some-auth-code} From there, I send that auth code to my API which will send it to WorkOS in exchange for the user's session token and user object. I then store the session token in a cookie (this works). on the next line, I update the authStore loggedIn property to true. If I do not redirect from the /callback to another page, the store is updated successfully. If I redirect using navigateTo('/) (or whatever value is in my referrer store), the loggedIn state is never updated. I'm using the following packages/versions
- nuxt ^3.13.2
- @pinia/nuxt ^0.5.5
- @pinia-plugin-persistedstate/nuxt ^1.2.1
- nuxt ^3.13.2
- @pinia/nuxt ^0.5.5
- @pinia-plugin-persistedstate/nuxt ^1.2.1
I've been able to trace the following: - App successfully exchanges the code for session token - SSR updates the authStore.loggedIn value as true. - If I use navigateTo('/') after setting loggedIn = true, state is never updated. - If I wait until CSR is complete, store is updated and persisted successfully. I'm also experiencing my useFetch call making a request on SSR & CSR, to which the CSR received an error since the auth code was already exchanged when the SSR used useFetch to perform the initial call I feel like I just need to know when the store is updated then issue the redirect but can't seem to figure it out πŸ€¦β€β™‚οΈ
1 Reply
Krd8ssb
Krd8ssbβ€’4h ago
Here's the basic setup I'm using (this is definitely not production ready - I've butchered it trying to find out what's going on) ~/stores/auth.store.ts
export const useAuthStore = defineStore('authStore', () => {
const loggedIn = ref<boolean>(false)
return { loggedIn }
}, {
persist: true
})

if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useAuthStore, import.meta.hot))
}
export const useAuthStore = defineStore('authStore', () => {
const loggedIn = ref<boolean>(false)
return { loggedIn }
}, {
persist: true
})

if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useAuthStore, import.meta.hot))
}
~/pages/callback.vue
<script lang="ts" setup>
import type { WorkOsUser } from '~/stores/users.store'

function generateExpires() {
const now = new Date()
const time = now.getTime()
return new Date(time + (60 * 60 * 24 * 90))
}

const errorStore = useErrorStore()
const runtimeConfig = useRuntimeConfig()

const authStore = useAuthStore()
const { loggedIn } = storeToRefs(authStore)

const expires = generateExpires()
const authCookie = useCookie('wos-session', { expires, sameSite: 'lax', secure: true, httpOnly: true })

const { query } = useRoute()
const code = query.code
const { data, error } = await useFetch<{
session: string
user: WorkOsUser
}>(`${runtimeConfig.public.apiHost}/auth/callback`, {
query: { code }
})

if (!authStore.loggedIn) {
if (data.value?.session) {
authCookie.value = data.value.session
loggedIn.value = true
await navigateTo('/')
}

if (error.value) {
errorStore.setError({ ...error.value.data, show: true })
if (errorStore.code === 'AUTHENTICATION_TOKEN_INVALID_OR_EXPIRED') {
errorStore.message = 'Redirecting to authenticate...'
}
}
}

await navigateTo('/')
</script>

<template>
<div>
<UContainer>
<AppError v-if="errorStore?.show"/>
<UAlert
v-else
variant="subtle"
color="blue"
>
Starting Authentication...
</UAlert>
</UContainer>
</div>
</template>

<style scoped></style>
<script lang="ts" setup>
import type { WorkOsUser } from '~/stores/users.store'

function generateExpires() {
const now = new Date()
const time = now.getTime()
return new Date(time + (60 * 60 * 24 * 90))
}

const errorStore = useErrorStore()
const runtimeConfig = useRuntimeConfig()

const authStore = useAuthStore()
const { loggedIn } = storeToRefs(authStore)

const expires = generateExpires()
const authCookie = useCookie('wos-session', { expires, sameSite: 'lax', secure: true, httpOnly: true })

const { query } = useRoute()
const code = query.code
const { data, error } = await useFetch<{
session: string
user: WorkOsUser
}>(`${runtimeConfig.public.apiHost}/auth/callback`, {
query: { code }
})

if (!authStore.loggedIn) {
if (data.value?.session) {
authCookie.value = data.value.session
loggedIn.value = true
await navigateTo('/')
}

if (error.value) {
errorStore.setError({ ...error.value.data, show: true })
if (errorStore.code === 'AUTHENTICATION_TOKEN_INVALID_OR_EXPIRED') {
errorStore.message = 'Redirecting to authenticate...'
}
}
}

await navigateTo('/')
</script>

<template>
<div>
<UContainer>
<AppError v-if="errorStore?.show"/>
<UAlert
v-else
variant="subtle"
color="blue"
>
Starting Authentication...
</UAlert>
</UContainer>
</div>
</template>

<style scoped></style>
I was able to get it to redirect correctly by updating the following ~/pages/callback.vue:
const authStore = useAuthStore()
const { loggedIn } = storeToRefs(authStore)

if (import.meta.client) {
await navigateTo('/')
}
const authStore = useAuthStore()
const { loggedIn } = storeToRefs(authStore)

if (import.meta.client) {
await navigateTo('/')
}
By the time the client loaded, the data was in the store as I had expected and redirected the user to the homepage successfully. I'm sure there's a better way to do this but at least it's working to continue on with a POC
Want results from more Discord servers?
Add your server