Vue cookbook · Beginner
Protect routes with Vue Router navigation guards
Logged-out users can open account pages, and after login they lose the page they wanted.
Approach
Mark routes with meta.requiresAuth, check the session in a global beforeEach guard, redirect to login with
the original path, and return there after logging in.
Solution
// router.ts
import { createRouter, createWebHistory } from "vue-router";
import { useSession } from "./stores/session";
declare module "vue-router" {
interface RouteMeta {
requiresAuth?: boolean;
role?: "admin";
}
}
export const router = createRouter({
history: createWebHistory(),
routes: [
{ path: "/", component: () => import("./pages/Home.vue") },
{ path: "/login", component: () => import("./pages/Login.vue") },
{ path: "/account", component: () => import("./pages/Account.vue"), meta: { requiresAuth: true } },
{ path: "/admin", component: () => import("./pages/Admin.vue"), meta: { requiresAuth: true, role: "admin" } },
],
});
router.beforeEach(async (to) => {
const session = useSession();
if (!session.loaded) await session.load(); // e.g. GET /api/me once
if (to.meta.requiresAuth && !session.user) {
return { path: "/login", query: { redirect: to.fullPath } };
}
if (to.meta.role && session.user?.role !== to.meta.role) return { path: "/" };
});
Pitfalls
- Treating route guards as security; the API must check permissions on every request.
- Accepting any
redirectquery value after login (open redirect); only allow paths starting with/. - Calling
/api/meon every navigation; load once and cache in the store.
Variations
- Per-route
beforeEnterguards for one-off checks. - In Nuxt, use route middleware (
definePageMeta({ middleware: "auth" })).
Further reading: Navigation guards
Reference: https://router.vuejs.org/guide/advanced/navigation-guards.html
More Vue recipes
- Access child component methods with template refs and defineExpose
- Add SEO metadata and structured data in Nuxt
- Build an accessible modal with Teleport
- Build custom inputs with defineModel and modifiers
- Catch component errors with an error boundary
- Debounce user input with a custom ref
- Fetch data in a composable and cancel stale requests
- Fetch, refresh and share data with Nuxt useFetch