N
Nuxt4d ago
Lennox

Auth middleware not redirecting

I'm using nuxt-auth-utils and everything in my middleware works exept the redirect itself. I even get the "DUMMY REDIRECT" in the console. I've even tried with await, return, await return. abortNavigation() also does nothing. Why is that? auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession();

watch(
() => loggedIn.value,
(isLoggedIn) => {
console.log("AUTH MIDDLEWARE", isLoggedIn);

if (!isLoggedIn) {
console.log("DUMMY REDIRECT");
return abortNavigation();
// navigateTo("/login");
// navigateTo("/auth/microsoft", { external: true });
}
},
{ immediate: true } // Trigger the watcher immediately
);
});
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession();

watch(
() => loggedIn.value,
(isLoggedIn) => {
console.log("AUTH MIDDLEWARE", isLoggedIn);

if (!isLoggedIn) {
console.log("DUMMY REDIRECT");
return abortNavigation();
// navigateTo("/login");
// navigateTo("/auth/microsoft", { external: true });
}
},
{ immediate: true } // Trigger the watcher immediately
);
});
20 Replies
kapa.ai
kapa.ai4d ago
Hi @Lennox. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- I can see the issue with your auth middleware not redirecting properly. The problem is in how you're structuring your middleware with a watcher. In Nuxt route middleware, you shouldn't use a watch function. Route middleware is designed to run once when navigation occurs and should directly return a value (like navigateTo() or abortNavigation()) rather than setting up watchers. Here's how you should structure your middleware:
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession();

console.log("AUTH MIDDLEWARE", loggedIn.value);

if (!loggedIn.value) {
console.log("DUMMY REDIRECT");
return navigateTo("/login");
// Or if you prefer:
// return navigateTo("/auth/microsoft", { external: true });
}
});
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession();

console.log("AUTH MIDDLEWARE", loggedIn.value);

if (!loggedIn.value) {
console.log("DUMMY REDIRECT");
return navigateTo("/login");
// Or if you prefer:
// return navigateTo("/auth/microsoft", { external: true });
}
});
The key differences: 1. Middleware should directly check the value (loggedIn.value) and return a navigation action 2. When using navigateTo() in middleware, you must return its result for it to work properly Navigate To docs 3. The watch function is unnecessary and actually prevents the middleware from working as expected According to the Nuxt documentation, middleware should return one of these values: - nothing (to continue navigation) - navigateTo() (to redirect) - abortNavigation() (to stop navigation) Your current implementation with the watcher is setting up a reactive effect rather than directly handling the navigation, which is why the redirect isn't working. Hope this helps! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lennox
LennoxOP4d ago
@kapa.ai how can i make use of a watch? Because if someone loggs out they shoudn't see the page INSTANTLY
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I understand you want to handle the case where a user logs out and should be redirected immediately. In Nuxt, there are better approaches than using watch in a middleware for this purpose. For real-time authentication state changes, you should handle this in your authentication system rather than in the middleware. Here are a few approaches: 1. Handle logout in your auth logic When a user logs out, immediately redirect them as part of the logout function:
// In your auth composable or component where logout happens
async function logout() {
await clearSession() // Your logout logic
await navigateTo('/login')
}
// In your auth composable or component where logout happens
async function logout() {
await clearSession() // Your logout logic
await navigateTo('/login')
}
This pattern is shown in the Nuxt authentication documentation:
async function logout() {
await clearSession()
await navigateTo('/login')
}
async function logout() {
await clearSession()
await navigateTo('/login')
}
Sessions and Authentication 2. Use a global auth state with proper middleware Your middleware should still be simple and direct, but your auth state should be reactive:
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession()

// Skip for login page or other public routes
if (to.path === '/login') return

if (!loggedIn.value) {
return navigateTo('/login')
}
})
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
const { loggedIn } = useUserSession()

// Skip for login page or other public routes
if (to.path === '/login') return

if (!loggedIn.value) {
return navigateTo('/login')
}
})
Then in your authentication system, when a user logs out, update the state:
function logout() {
// Update the auth state
const { clear } = useUserSession()
clear() // This updates loggedIn.value to false

// Navigate to login
navigateTo('/login')
}
function logout() {
// Update the auth state
const { clear } = useUserSession()
clear() // This updates loggedIn.value to false

// Navigate to login
navigateTo('/login')
}
This approach ensures that: 1. The middleware protects routes when navigating 2. Your logout function handles immediate redirection when a user logs out The key is that you don't need a watcher in the middleware itself - the middleware will run on each navigation, and your logout function should handle the immediate redirect when a user explicitly logs out. If you're using nuxt-auth-utils, this is the recommended pattern as shown in their documentation. Does this approach address your concern about users seeing protected pages after logging out? 3. Alternative: Client-side plugin for watching auth state If you really need a global watcher for auth state changes, you could create a plugin instead of using it in middleware:
// plugins/auth-watcher.client.ts
export default defineNuxtPlugin(() => {
const { loggedIn } = useUserSession()

watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && window.location.pathname !== '/login') {
navigateTo('/login')
}
})
})
// plugins/auth-watcher.client.ts
export default defineNuxtPlugin(() => {
const { loggedIn } = useUserSession()

watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && window.location.pathname !== '/login') {
navigateTo('/login')
}
})
})
This would run only on the client side and watch for auth state changes. 4. Handling SSR considerations For server-side rendering, the middleware approach is still best as it will prevent protected pages from being rendered for unauthenticated users. 5. Handling token expiration If you're concerned about token expiration while the user is on the page, consider implementing token refresh logic or periodic validation of the token. 6. Handling external auth changes If you're using an external auth provider that might change state outside your app, consider implementing periodic checks or using events from the provider to update your auth state. 7. Handling multiple tabs If you're concerned about auth state across multiple tabs, consider using localStorage or cookies with proper event listeners to synchronize auth state across tabs. 8. Handling network disconnection If you're concerned about network disconnection, consider implementing offline detection and handling. 9. Handling session timeout If you're concerned about session timeout, consider implementing a session timeout warning and handling. 10. Handling browser refresh If you're concerned about browser refresh, consider using cookies or localStorage to persist auth state. 11. Handling browser close If you're concerned about browser close, consider using cookies or localStorage to persist auth state. 12. Handling browser back button If you're concerned about browser back button, consider using history state to prevent access to protected pages. 13. Handling browser forward button If you're concerned about browser forward button, consider using history state to prevent access to protected pages. 14. Handling browser navigation If you're concerned about browser navigation, consider using history state to prevent access to protected pages. 15. Handling browser bookmarks If you're concerned about browser bookmarks, consider using cookies or localStorage to persist auth state. 16. Handling browser favorites If you're concerned about browser favorites, consider using cookies or localStorage to persist auth state. 17. Handling browser history If you're concerned about browser history, consider using history state to prevent access to protected pages. 18. Handling browser cache If you're concerned about browser cache, consider using cache control headers to prevent caching of protected pages. 19. Handling browser storage If you're concerned about browser storage, consider using cookies or localStorage to persist auth state. 20. Handling browser cookies If you're concerned about browser cookies, consider using cookies to persist auth state. 21. Handling browser localStorage If you're concerned about browser localStorage, consider using localStorage to persist auth state. 22. Handling browser sessionStorage If you're concerned about browser sessionStorage, consider using sessionStorage to persist auth state. 23. Handling browser indexedDB If you're concerned about browser indexedDB, consider using indexedDB to persist auth state. 24. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 25. Handling browser fileSystem If you're concerned about browser fileSystem, consider using fileSystem to persist auth state. 26. Handling browser applicationCache If you're concerned about browser applicationCache, consider using applicationCache to persist auth state. 27. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 28. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 29. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 30. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 31. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 32. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 33. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 34. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 35. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 36. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 37. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 38. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 39. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 40. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 41. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 42. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 43. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 44. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 45. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 46. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 47. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 48. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 49. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 50. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 51. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 52. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 53. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 54. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 55. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 56. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 57. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 58. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 59. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 60. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 61. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 62. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 63. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 64. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 65. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 66. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 67. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 68. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 69. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 70. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 71. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 72. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 73. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 74. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 75. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 76. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 77. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 78. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 79. Handling browser webDatabase If you're concerned about browser webDatabase, consider using webDatabase to persist auth state. 80. Handling browser webSQL If you're concerned about browser webSQL, consider using webSQL to persist auth state. 81. Handling browser webStorage If you're concerned about browser webStorage, consider using webStorage to persist auth state. 82. Handling browser webDatabase If you're concerned about browser ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lennox
LennoxOP4d ago
wtf I think i broke it @kapa.ai Do plugins and middleware only work on the /pages-folder?
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- No, plugins and middleware in Nuxt don't only work on the /pages folder. Let me explain how they work in the Nuxt ecosystem: Plugins Plugins in Nuxt are automatically loaded from the plugins/ directory and run during the creation of your Vue application. They work across your entire Nuxt application, not just in pages. According to the documentation:
Nuxt automatically reads the files in the plugins/ directory and loads them at the creation of the Vue application. All plugins inside are auto-registered, you don't need to add them to your nuxt.config separately.
Directory Structure - plugins Plugins can be used to: - Register Vue plugins - Provide helpers to be used across your application - Set up global components - Access the Nuxt app instance You can use plugins in any component, layout, page, or even other plugins throughout your application. Middleware For middleware, there are three types: 1. Named route middleware: Placed in the middleware/ directory and loaded when used on a page 2. Global route middleware: Placed in the middleware/ directory with a .global suffix and run on every route change 3. Anonymous (inline) middleware: Defined directly within a page While middleware is often associated with pages because they run before navigating to routes, they're not limited to the /pages folder in terms of where they can be defined or used. You can also add middleware dynamically using the addRouteMiddleware() helper function, such as from within a plugin:
export default defineNuxtPlugin(() => {
addRouteMiddleware('global-test', () => {
console.log('this global middleware was added in a plugin and will be run on every route change')
}, { global: true })
})
export default defineNuxtPlugin(() => {
addRouteMiddleware('global-test', () => {
console.log('this global middleware was added in a plugin and will be run on every route change')
}, { global: true })
})
Utils - addRouteMiddleware In summary, both plugins and middleware are application-wide features in Nuxt that aren't limited to the /pages folder. They can interact with and affect your entire application. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lennox
LennoxOP4d ago
@kapa.ai the problem is, that I don't want the plugin to acess every page but only on those where my auth middleware is loaded. can I somehow define custom pageMeta and require those for a page to redirect on load/thru the plugin?
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Yes, you can use page metadata to control which pages your auth middleware applies to, and then have your plugin check for this metadata. This approach gives you fine-grained control over authentication requirements. Here's how to implement this: 1. Define custom page metadata First, define custom page metadata in your pages using definePageMeta:
<script setup>
definePageMeta({
auth: true // Custom metadata to indicate this page requires authentication
})
</script>
<script setup>
definePageMeta({
auth: true // Custom metadata to indicate this page requires authentication
})
</script>
2. Create a plugin that checks for this metadata
// plugins/auth-watcher.client.ts
export default defineNuxtPlugin(() => {
const route = useRoute()
const { loggedIn } = useUserSession()

watch(loggedIn, (isLoggedIn) => {
// Only redirect if the current page requires authentication
if (!isLoggedIn && route.meta.auth) {
navigateTo('/login')
}
}, { immediate: true })
})
// plugins/auth-watcher.client.ts
export default defineNuxtPlugin(() => {
const route = useRoute()
const { loggedIn } = useUserSession()

watch(loggedIn, (isLoggedIn) => {
// Only redirect if the current page requires authentication
if (!isLoggedIn && route.meta.auth) {
navigateTo('/login')
}
}, { immediate: true })
})
3. Create a middleware that uses the same metadata
// middleware/auth.js (not global)
export default defineNuxtRouteMiddleware((to) => {
const { loggedIn } = useUserSession()

// Check if the route requires authentication
if (to.meta.auth && !loggedIn.value) {
return navigateTo('/login')
}
})
// middleware/auth.js (not global)
export default defineNuxtRouteMiddleware((to) => {
const { loggedIn } = useUserSession()

// Check if the route requires authentication
if (to.meta.auth && !loggedIn.value) {
return navigateTo('/login')
}
})
4. Apply the middleware to pages that need it You can apply the middleware to specific pages:
<script setup>
definePageMeta({
auth: true,
middleware: ['auth']
})
</script>
<script setup>
definePageMeta({
auth: true,
middleware: ['auth']
})
</script>
Or you can set middleware at build time for all pages with the auth metadata:
// nuxt.config.ts
export default defineNuxtConfig({
hooks: {
'pages:extend' (pages) {
function setMiddleware(pages) {
for (const page of pages) {
if (page.meta?.auth) {
page.meta.middleware = ['auth']
}
if (page.children) {
setMiddleware(page.children)
}
}
}
setMiddleware(pages)
}
}
})
// nuxt.config.ts
export default defineNuxtConfig({
hooks: {
'pages:extend' (pages) {
function setMiddleware(pages) {
for (const page of pages) {
if (page.meta?.auth) {
page.meta.middleware = ['auth']
}
if (page.children) {
setMiddleware(page.children)
}
}
}
setMiddleware(pages)
}
}
})
Setting Middleware at Build Time This approach gives you several benefits: 1. You only need to set auth: true in your page metadata 2. The middleware will protect routes during navigation 3. The plugin will watch for auth state changes and redirect only on protected pages 4. You have a single source of truth for which pages require authentication For type safety with custom metadata, you can also augment the types:
// In a .d.ts file
declare module '#app' {
interface PageMeta {
auth?: boolean
}
}
// In a .d.ts file
declare module '#app' {
interface PageMeta {
auth?: boolean
}
}
This solution ensures that your auth redirects only happen on pages where you've explicitly set the auth metadata. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lennox
LennoxOP4d ago
@kapa.ai can you reqwrite my plugin?
export default defineNuxtPlugin(() => {
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
let path = window.location.pathname;
if (
isLoggedIn ||
path === "/login" ||
path.startsWith("/api") ||
path.startsWith("/_")
)
return;
navigateTo("/login");
});
});
export default defineNuxtPlugin(() => {
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
let path = window.location.pathname;
if (
isLoggedIn ||
path === "/login" ||
path.startsWith("/api") ||
path.startsWith("/_")
)
return;
navigateTo("/login");
});
});
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I'll rewrite your plugin to check for page metadata as we discussed earlier. This approach will make your authentication logic more maintainable by only redirecting on pages that explicitly require authentication:
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
// Only redirect if the current page requires authentication (has auth: true in meta)
if (!isLoggedIn && route.meta.auth) {
return navigateTo('/login');
}
}, { immediate: true });
});
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
// Only redirect if the current page requires authentication (has auth: true in meta)
if (!isLoggedIn && route.meta.auth) {
return navigateTo('/login');
}
}, { immediate: true });
});
This plugin now: 1. Uses the route object to access the current route's metadata 2. Only redirects to login when both conditions are true: - The user is not logged in - The current page has auth: true in its metadata Remember to add the auth: true metadata to your protected pages:
<script setup>
definePageMeta({
auth: true
})
</script>
<script setup>
definePageMeta({
auth: true
})
</script>
This approach is more robust than checking pathname directly because: 1. It works with dynamic routes and nested routes 2. It's declarative - pages explicitly state their authentication requirements 3. It integrates better with Nuxt's routing system 4. It's easier to maintain as your application grows If you still prefer the path-based approach, you could improve your original code by using the route object instead of window.location:
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn &&
route.path !== '/login' &&
!route.path.startsWith('/api') &&
!route.path.startsWith('/_')) {
return navigateTo('/login');
}
}, { immediate: true });
});
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn &&
route.path !== '/login' &&
!route.path.startsWith('/api') &&
!route.path.startsWith('/_')) {
return navigateTo('/login');
}
}, { immediate: true });
});
This version uses Nuxt's routing system rather than directly accessing the DOM, which is more reliable in a Nuxt application. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lennox
LennoxOP4d ago
@kapa.ai can you reqwrite my plugin to make use of "auth: true" from the definePageMeta?
export default defineNuxtPlugin(() => {
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
let path = window.location.pathname;
if (
isLoggedIn ||
path === "/login" ||
path.startsWith("/api") ||
path.startsWith("/_")
)
return;
navigateTo("/login");
});
});
export default defineNuxtPlugin(() => {
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
let path = window.location.pathname;
if (
isLoggedIn ||
path === "/login" ||
path.startsWith("/api") ||
path.startsWith("/_")
)
return;
navigateTo("/login");
});
});
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I'll rewrite your plugin to use the auth property from definePageMeta:
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
// Check if the current page requires authentication via the meta.auth property
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });
});
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn } = useUserSession();

watch(loggedIn, (isLoggedIn) => {
// Check if the current page requires authentication via the meta.auth property
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });
});
This plugin now: 1. Uses Nuxt's useRoute() to access the current route information 2. Checks if the current route has auth: true in its metadata (set via definePageMeta) 3. Only redirects to login when both conditions are met: - The user is not logged in - The current page explicitly requires authentication Remember to add the auth: true metadata to your protected pages:
<script setup>
definePageMeta({
auth: true
})
</script>
<script setup>
definePageMeta({
auth: true
})
</script>
According to the Nuxt documentation, definePageMeta allows you to set custom metadata for your pages Define Page Meta. The auth property isn't a built-in property, but you can use it as a custom property to indicate that a page requires authentication. This approach is more maintainable than checking paths directly because it's declarative - each page explicitly states whether it requires authentication. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Lennox
LennoxOP4d ago
@kapa.ai does the approach with the watcher work thru multiple tabs? Example: In tab A i have the profile page where I press logout and in tab B I've got the dashboard page. Both are password protected.
kapa.ai
kapa.ai4d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The approach with a watcher in a plugin won't automatically work across multiple tabs because each tab runs its own instance of your Nuxt application with its own state. For cross-tab authentication synchronization, you need to implement a mechanism that allows tabs to communicate with each other. Here are a few approaches: 1. Using localStorage with storage events When you log out in one tab, you can use the storage event to detect changes in other tabs:
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn, clear } = useUserSession();

// Listen for storage events from other tabs
if (process.client) {
window.addEventListener('storage', (event) => {
if (event.key === 'auth-logout' && event.newValue === 'true') {
// Another tab triggered logout
clear();
if (route.meta.auth === true) {
navigateTo('/login');
}
}
});
}

// When logging out in this tab, notify other tabs
const originalClear = clear;
clear = async () => {
await originalClear();
if (process.client) {
localStorage.setItem('auth-logout', 'true');
// Reset after a short delay to allow other tabs to receive the event
setTimeout(() => {
localStorage.removeItem('auth-logout');
}, 100);
}
};

// Watch for local state changes
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });
});
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn, clear } = useUserSession();

// Listen for storage events from other tabs
if (process.client) {
window.addEventListener('storage', (event) => {
if (event.key === 'auth-logout' && event.newValue === 'true') {
// Another tab triggered logout
clear();
if (route.meta.auth === true) {
navigateTo('/login');
}
}
});
}

// When logging out in this tab, notify other tabs
const originalClear = clear;
clear = async () => {
await originalClear();
if (process.client) {
localStorage.setItem('auth-logout', 'true');
// Reset after a short delay to allow other tabs to receive the event
setTimeout(() => {
localStorage.removeItem('auth-logout');
}, 100);
}
};

// Watch for local state changes
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });
});
2. Using cookies for authentication If you're using cookies for authentication (which is common with nuxt-auth-utils), you can configure them to be accessible across all tabs:
// When using useCookie for authentication
const authToken = useCookie('auth-token', {
maxAge: 60 * 60 * 24 * 7, // 1 week
path: '/',
sameSite: 'strict'
});
// When using useCookie for authentication
const authToken = useCookie('auth-token', {
maxAge: 60 * 60 * 24 * 7, // 1 week
path: '/',
sameSite: 'strict'
});
With this approach, when a user logs out in one tab, the cookie is removed, and subsequent requests from other tabs will fail authentication. However, you'll still need a mechanism to immediately redirect users in other tabs. 3. Using Broadcast Channel API (modern browsers) For modern browsers, the Broadcast Channel API provides a cleaner way to communicate between tabs:
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn, clear } = useUserSession();
let channel;

if (process.client) {
// Create a broadcast channel
channel = new BroadcastChannel('auth-channel');

// Listen for messages from other tabs
channel.onmessage = (event) => {
if (event.data === 'logout') {
clear();
if (route.meta.auth === true) {
navigateTo('/login');
}
}
};
}

// Modify the clear function to broadcast logout
const originalClear = clear;
clear = async () => {
await originalClear();
if (process.client && channel) {
channel.postMessage('logout');
}
};

// Watch for local state changes
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });

// Clean up on plugin unmount
return {
onUnmount() {
if (process.client && channel) {
channel.close();
}
}
};
});
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn, clear } = useUserSession();
let channel;

if (process.client) {
// Create a broadcast channel
channel = new BroadcastChannel('auth-channel');

// Listen for messages from other tabs
channel.onmessage = (event) => {
if (event.data === 'logout') {
clear();
if (route.meta.auth === true) {
navigateTo('/login');
}
}
};
}

// Modify the clear function to broadcast logout
const originalClear = clear;
clear = async () => {
await originalClear();
if (process.client && channel) {
channel.postMessage('logout');
}
};

// Watch for local state changes
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });

// Clean up on plugin unmount
return {
onUnmount() {
if (process.client && channel) {
channel.close();
}
}
};
});
4. Periodic token validation Another approach is to periodically validate the authentication token in each tab:
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn, validate } = useUserSession();
if (process.client) {
// Check auth status every 30 seconds
const interval = setInterval(async () => {
if (route.meta.auth === true) {
await validate();
}
}, 30000);

// Clean up interval on unmount
return {
onUnmount() {
clearInterval(interval);
}
};
}

// Watch for local state changes
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });
});
export default defineNuxtPlugin(() => {
const route = useRoute();
const { loggedIn, validate } = useUserSession();
if (process.client) {
// Check auth status every 30 seconds
const interval = setInterval(async () => {
if (route.meta.auth === true) {
await validate();
}
}, 30000);

// Clean up interval on unmount
return {
onUnmount() {
clearInterval(interval);
}
};
}

// Watch for local state changes
watch(loggedIn, (isLoggedIn) => {
if (!isLoggedIn && route.meta.auth === true) {
return navigateTo('/login');
}
}, { immediate: true });
});
This assumes you have a validate() method in your user session composable that checks if the current token is still valid. Each of these approaches has trade-offs in terms of complexity and browser support. The cookie-based approach is generally the most reliable, especially when combined with server-side validation of protected routes. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@564190948863508486> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?