N
Nuxt4mo ago
lav

Middleare for Auth

Hello, I was wondering what is the best way to verify if user is logged in before showing route, I am doing a basic test right now via localStorage variable in real life I would have my state in local storage or global store saying i am logged in with an http cookie.
export default defineNuxtRouteMiddleware((to, from) => {
if (import.meta.server) return;

console.log(localStorage.getItem('loggedIn'));

if (localStorage.getItem('loggedIn') !== 'true') {
return navigateTo('/sign-in');
}
});
export default defineNuxtRouteMiddleware((to, from) => {
if (import.meta.server) return;

console.log(localStorage.getItem('loggedIn'));

if (localStorage.getItem('loggedIn') !== 'true') {
return navigateTo('/sign-in');
}
});
Is there a way so the user is not even able to see the other page before the redirect?
7 Replies
oneeach
oneeach4mo ago
you would need to make your middleware global to apply to all pages or you can define which middleware applies to a specific page by adding it to your PageMeta: definePageMeta({ middleware: 'auth' }) If you go with the global method, you would then need to specify which routes are accessible to users not logged in with something like this: definePageMeta({ auth: false, }) To make middleware global, just append 'global.ts' to the filename. like auth.global.ts it's also good practice to throw an error to notify users they are trying to access an unauthorized page with something like this in your middleware: if (!localStorage.getItem('loggedIn')) { throw createError({ statusCode: 403, statusMessage: 'Unauthorized' }) }
lav
lavOP4mo ago
@oneeach So this is the way, I need to disable server side check since this is for local storage too. Is it normal that I can see the page a bit render before the navigate back to login> Thanks! If you go with the global method, you would then need to specify which routes are accessible to users not logged in with something like this: definePageMeta({ auth: false, }) This does not work, I do not see it in the doc
export default defineNuxtRouteMiddleware((to, from) => {
if (from.path === '/' || from.path === '/sign-in') return;

if (import.meta.server) return;

if (!localStorage.getItem('loggedIn')) {
navigateTo('/sign-in');
throw createError({ statusCode: 403, statusMessage: 'Unauthorized' });
}
});
export default defineNuxtRouteMiddleware((to, from) => {
if (from.path === '/' || from.path === '/sign-in') return;

if (import.meta.server) return;

if (!localStorage.getItem('loggedIn')) {
navigateTo('/sign-in');
throw createError({ statusCode: 403, statusMessage: 'Unauthorized' });
}
});
I did this at the place @oneeach
oneeach
oneeach4mo ago
no, it's not normal. The middleware should run before you can see the page. Where are you putting your middleware? Can you recreate your middleware here: https://nuxt.new/s/v3
StackBlitz
Nuxt - Starter - StackBlitz
Create a new Nuxt project, module, layer or start from a theme with our collection of starters.
lav
lavOP4mo ago
@oneeach throwing an exception because the user went on a route not auth is pretty bad imo, cuz it crash the flow if I put this
export default defineNuxtRouteMiddleware((to, from) => {
if (import.meta.server) return;
console.log('here');

// if (!localStorage.getItem('loggedIn')) {
// console.log('here');
// navigateTo('/');
// }
return navigateTo('/sign-in');
});
export default defineNuxtRouteMiddleware((to, from) => {
if (import.meta.server) return;
console.log('here');

// if (!localStorage.getItem('loggedIn')) {
// console.log('here');
// navigateTo('/');
// }
return navigateTo('/sign-in');
});
With global I have infinite redirect I removed it from global and now I have hydration error:
runtime-core.esm-bun…er.js?v=3826bf5e:47 [Vue warn]: Hydration node mismatch:
- rendered on server:
(text)
- expected on client: div
at <SignIn onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <Anonymous key="/sign-in" vnode=
{__v_isVNode: true, __v_skip: true, type: {…}, props: {…}, key: null, …}
route=
{fullPath: '/sign-in', hash: '', query: {…}, name: 'sign-in', path: '/sign-in', …}
... >
at <RouterView name=undefined route=undefined >
at <NuxtPage>
at <NuxtLayoutProvider layoutProps=
{ref: RefImpl}
key="default" name="default" ... >
at <NuxtLayout>
at <App key=4 >
at <NuxtRoot>
runtime-core.esm-bun….js?v=3826bf5e:3730 Hydration completed but contains mismatches.
runtime-core.esm-bun…er.js?v=3826bf5e:47 [Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core .
at <NuxtLayoutProvider layoutProps=
{ref: RefImpl}
key="default" name="default" ... >
at <NuxtLayout>
at <App key=4 >
at <NuxtRoot>
runtime-dom.esm-bundler.js?v=3826bf5e:15 Uncaught (in promise) DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
at insert (
runtime-core.esm-bun…er.js?v=3826bf5e:47 [Vue warn]: Hydration node mismatch:
- rendered on server:
(text)
- expected on client: div
at <SignIn onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <Anonymous key="/sign-in" vnode=
{__v_isVNode: true, __v_skip: true, type: {…}, props: {…}, key: null, …}
route=
{fullPath: '/sign-in', hash: '', query: {…}, name: 'sign-in', path: '/sign-in', …}
... >
at <RouterView name=undefined route=undefined >
at <NuxtPage>
at <NuxtLayoutProvider layoutProps=
{ref: RefImpl}
key="default" name="default" ... >
at <NuxtLayout>
at <App key=4 >
at <NuxtRoot>
runtime-core.esm-bun….js?v=3826bf5e:3730 Hydration completed but contains mismatches.
runtime-core.esm-bun…er.js?v=3826bf5e:47 [Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core .
at <NuxtLayoutProvider layoutProps=
{ref: RefImpl}
key="default" name="default" ... >
at <NuxtLayout>
at <App key=4 >
at <NuxtRoot>
runtime-dom.esm-bundler.js?v=3826bf5e:15 Uncaught (in promise) DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
at insert (
Because the server does not render the same as client, that's normal bcs I am looking in local storage if he is logged in but I see the dashboard on page load before the redirect https://stackblitz.com/edit/github-rwecso?file=middleware%2Fauth.js,pages%2Ftest.vue I still see the page dashboard and have the error on console above Should I handle the login state in the global store at the place so I can use the middleware server side? If so, is there also a way client side for redirect without having console error? w/ ssr it works perfect, but I have no clue for client side redirect, that would be my question now since it can happen in the future i have this to do
export default defineNuxtRouteMiddleware((to, from) => {
const isLoggedIn = useState('isLoggedIn');

if (to.path === '/') {
return;
}

if (to.path === '/sign-in' && isLoggedIn.value) {
return navigateTo('/dashboard');
} else if (to.path === '/sign-in' && !isLoggedIn.value) {
return;
}

if (!isLoggedIn.value) {
return navigateTo('/sign-in');
}
});
export default defineNuxtRouteMiddleware((to, from) => {
const isLoggedIn = useState('isLoggedIn');

if (to.path === '/') {
return;
}

if (to.path === '/sign-in' && isLoggedIn.value) {
return navigateTo('/dashboard');
} else if (to.path === '/sign-in' && !isLoggedIn.value) {
return;
}

if (!isLoggedIn.value) {
return navigateTo('/sign-in');
}
});
@oneeach any idea?
sexyGaming - Kiroma
Never trust the user controled data, esp. in such cases as if he is logged in and as whom he is logged in. So local storage can be tampered with and then the user is logged in because someone set a value to true and/or changed the userid in there and now impersonated it. (Okay if you have session management then this may be a bit exaggerated because you would need to know the session but the point stands) So yes you also have to check it server side when he initially comes and redirect him away. If the session timed out in the client then you need to also handle that in a middleware. Multiple ways you can go there. Either force reload and let the server handle the redirect or implement the logic you have written there. Your middleware for protected pages should only be triggered on protected pages. Register and Login, or the landingpage, would not have the authentication middleware or, as another user already stated, you could disable that via custom page meta. Thus you would not need to check the current path. If it is global and you don't use a custom property to disable it, then you will need to do the routes checking from your example.
sexyGaming - Kiroma
But to answer your specific problem, as your stack blitz was a bit too minimal, this is what you want to achieve? https://stackblitz.com/edit/github-rwecso-79iacs?file=pages%2Findex.vue
Christoph Landsdorf
StackBlitz
Nuxt - Starter (forked) - StackBlitz
Create a new Nuxt project, module, layer or start from a theme with our collection of starters.
lav
lavOP4mo ago
Since it is stack blitz I can't change the url in the search but I think via csr, before the redirect we will be able to see the page we want to access for a quick sec no?
Want results from more Discord servers?
Add your server