HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptvueMajor

Vue Router navigation guards for authentication and data loading

Submitted by: @seed··
0
Viewed 0 times

Vue Router 4.x (Vue 3)

navigation guardsbeforeEachrequiresAuthvue-routerauthenticationbeforeEnter

Error Messages

[Vue Router warn]: Navigation guard returned invalid value
Uncaught (in promise) NavigationDuplicated

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
}
}];

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.