Nuxt SSR redirection from external site

Hello everyone, When a user goes through a Stripe Checkout and returns via a link like:
<a class="Link NTVCZeIn__BusinessLink Link--primary" href="http://localhost:3000/en/workspace" aria-label="Back to TRANSCRI" title="TRANSCRI" target="_self" data-testid="business-link">
<a class="Link NTVCZeIn__BusinessLink Link--primary" href="http://localhost:3000/en/workspace" aria-label="Back to TRANSCRI" title="TRANSCRI" target="_self" data-testid="business-link">
Nuxt doesn't perform a full SSR, the page loads entirely on the client side, and all middlewares are executed client-side only. This causes two major issues : My global middleware (middleware.global.js) is only executed on the client, even though it’s supposed to load the user from the server. Here's the middleware (That's the initialize() function which API request to /api/user):
export default defineNuxtRouteMiddleware(async to => {
const cookieConsentStore = useCookieConsentStore()
cookieConsentStore.initialize()

const userStore = useAuthStore()
await userStore.initialize()

if (userStore.authenticated) {
if (to.name !== undefined && !to.name.startsWith('workspace-choosing-plan') && userStore.user.subscription_plan.code === null) {
return navigateTo('/workspace/choosing-plan')
}

if (userStore.user.subscription_plan.code !== null) {
const creditStore = useCreditStore()
await creditStore.initialize()
}
}
})
export default defineNuxtRouteMiddleware(async to => {
const cookieConsentStore = useCookieConsentStore()
cookieConsentStore.initialize()

const userStore = useAuthStore()
await userStore.initialize()

if (userStore.authenticated) {
if (to.name !== undefined && !to.name.startsWith('workspace-choosing-plan') && userStore.user.subscription_plan.code === null) {
return navigateTo('/workspace/choosing-plan')
}

if (userStore.user.subscription_plan.code !== null) {
const creditStore = useCreditStore()
await creditStore.initialize()
}
}
})
My layout (and some conditionally displayed modals) rely on user, so my auth.js middleware redirects the user to /login, and only then comes back to /workspace after making a successfully XHR request to /api/user How can I avoid this issue? Has anyone experienced a similar behavior? It seems like this only happens on the current browser tab — if I open a new tab and go to the same URL, it behaves correctly and SSR works as expected. Thanks a lot in advance
3 Replies
kapa.ai
kapa.ai4mo ago
Hi @Lord Aurelion. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- This behavior is related to how Nuxt handles navigation and hydration when a user returns to your app from an external site (like Stripe Checkout) in the same browser tab. When navigating back via a link (not a full page reload), the browser may use its in-memory JavaScript context, causing Nuxt to perform a client-side navigation rather than a full SSR page load. As a result, your middleware only runs on the client, and you miss out on server-side initialization (such as loading the user from the server). Key points from the Nuxt documentation: - Nuxt middleware runs on both the server and the client. However, if the navigation is handled client-side (i.e., the app is already loaded in the browser), middleware will only execute in the client context. A full SSR (server-side render) only happens on a hard reload or when opening a new tab, which matches your observation that SSR works as expected in a new tab Nuxt Lifecycle: Execute Nuxt App Middleware. - When a redirect is performed on the server, the browser receives a Location: header and makes a fresh request, resetting all application state unless persisted in a cookie Nuxt Lifecycle: Setup Nitro Server. - If you need to ensure that certain logic (like loading the user from the server) always runs server-side, you must trigger a full page reload. Otherwise, client-side navigation will not re-execute server-side middleware or fetch server-side data. Why does this happen? - Returning from Stripe via a link in the same tab does not always trigger a full page reload. If the Nuxt app is already loaded, the navigation is handled client-side, so only client-side middleware runs. - Opening the link in a new tab or performing a hard reload triggers SSR, so server-side middleware runs as expected. Possible solutions: - Force a full reload: You can use a regular anchor tag with target="_self" (as in your example), but browser behavior may still optimize and use client-side navigation if the app is already loaded. To guarantee SSR, you could use window.location.href = '/en/workspace' in your external service's return link or instruct users to open the link in a new tab. - Persist user state in cookies: If you store authentication and user state in cookies, you can rehydrate the user on the client even if SSR is skipped, but this may not be as robust as a true server-side check. - Check for missing server data on the client: In your middleware, if you detect that user data is missing on the client, you could trigger a fetch to /api/user and update the store accordingly. This is a workaround, not a true SSR solution. Summary:
This is a limitation of how client-side navigation works in Nuxt and other SPA frameworks. To guarantee server-side middleware execution after returning from an external site, you need to ensure a full page reload occurs. Otherwise, you must handle user state restoration on the client side. If you need more granular control, you may need to architect your authentication and user-loading logic to work robustly in both server and client contexts, and ensure critical state is persisted in cookies or other storage accessible on both sides. I'm sorry, but the knowledge sources do not provide a built-in Nuxt configuration to force SSR on client-side navigations triggered by external links in the same tab. The described behavior is consistent with Nuxt's documented lifecycle and middleware execution model Nuxt Lifecycle: Execute Nuxt App Middleware Nuxt Lifecycle: Setup Nitro Server. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@248528665711869953> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lord Aurelion
Lord AurelionOP4mo ago
What the AI ​​responds to is not necessarily a possible possibility, I don't have control over how Stripe redirects I have found the solution, my auth cookie was in strict sameSite, works perfectly in Lax

Did you find this page helpful?