patternjavascriptvueMajor
Vue Router navigation guards for authentication and data loading
Viewed 0 times
Vue Router 4.x (Vue 3)
navigation guardsbeforeEachrequiresAuthvue-routerauthenticationbeforeEnter
Error Messages
Problem
Protected routes are not enforced, or data is loaded after the route renders causing flashes of empty content. Navigation guards are placed in the wrong scope.
Solution
Use global beforeEach for auth, and per-route beforeEnter or in-component guards for data:
// router/index.ts
import { createRouter } from 'vue-router';
import { useAuthStore } from '@/stores/auth';
const router = createRouter({ / ... / });
// Global guard — runs before every navigation
router.beforeEach(async (to, from) => {
const auth = useAuthStore();
await auth.initialize(); // ensure auth state loaded
if (to.meta.requiresAuth && !auth.isLoggedIn) {
// redirect to login, saving the intended URL
return { name: 'Login', query: { redirect: to.fullPath } };
}
if (to.meta.guestOnly && auth.isLoggedIn) {
return { name: 'Dashboard' };
}
});
// Per-route guard
const routes = [{
path: '/users/:id',
component: UserView,
async beforeEnter(to) {
const user = await fetchUser(to.params.id);
if (!user) return { name: 'NotFound' };
to.meta.user = user; // pass data to component
}
}];
// router/index.ts
import { createRouter } from 'vue-router';
import { useAuthStore } from '@/stores/auth';
const router = createRouter({ / ... / });
// Global guard — runs before every navigation
router.beforeEach(async (to, from) => {
const auth = useAuthStore();
await auth.initialize(); // ensure auth state loaded
if (to.meta.requiresAuth && !auth.isLoggedIn) {
// redirect to login, saving the intended URL
return { name: 'Login', query: { redirect: to.fullPath } };
}
if (to.meta.guestOnly && auth.isLoggedIn) {
return { name: 'Dashboard' };
}
});
// Per-route guard
const routes = [{
path: '/users/:id',
component: UserView,
async beforeEnter(to) {
const user = await fetchUser(to.params.id);
if (!user) return { name: 'NotFound' };
to.meta.user = user; // pass data to component
}
}];
Why
Navigation guards intercept route changes before the component mounts. Returning false or a route object from a guard redirects the user. Using meta fields to attach fetched data avoids extra API calls after the component mounts.
Gotchas
- Pinia stores must be used after createPinia() — call useStore() inside the guard function, not at module level
- beforeEach guards must return a value (or nothing) — missing return causes navigation to stall in some versions
- afterEach has no cancel ability — use it for analytics/logging only
- In-component onBeforeRouteLeave guard is useful for unsaved-changes confirmation
Code Snippets
In-component route leave guard
// Confirm before leaving unsaved form
import { onBeforeRouteLeave } from 'vue-router';
onBeforeRouteLeave((to, from) => {
if (isDirty.value) {
return window.confirm('Discard unsaved changes?');
}
});Context
When implementing authentication and data preloading with Vue Router guards
Revisions (0)
No revisions yet.