Creating protected routes with Vue3 and Vue-router
A typical frontend website has some routes which need users to be authenticated before access is granted. So, it is essential to protect those vulnerable routes against unauthorized access. Vue-router handles this efficiently through the help of navigation guards.
Therefore, in this article, we will discuss the various types of navigation guards and their use cases in a typical vue3 website.
What is Vue-router
Vue-router is a vue package provided to make navigation seamless in a vue3 codebase. It provides functions designed to make your routing, page transition, route protection etc. easier when navigating in a vue3 website.
What are Navigation Guards?
Navigation guards are functions used to protect routes by redirecting or cancelling navigation.
They are divided into various types which can be used for various use cases depending on your codebase structure and choice of usage.
Types of Navigation Guards
Navigation guards are of three types namely; global guards, per-route guards and in-component guards. Let's look at them in detail.
Global Guards
Global guards are always defined universally for all routes. It is of three types; global-before, global-resolve and global-after guards.
Global Before Guards are usually done by using the router.beforeEach method.
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/user',
name: 'user',
component: () => import('../views/UserView.vue')
}
]})
router.beforeEach((to, from)=> {
)
As you can see from the code above, the beforeEach method accepts an arrow function as its only parameter. This arrow function takes in two parameters; to and from
to is the route being navigated to and from is the route being navigated from.
They are triggered when a route is clicked and it keeps the route pending until the condition has been resolved, like an asynchronous function. And yes, you can make the global guard asynchronous by using the async keyword in front of the arrow function.
When a condition has been resolved, you can either cancel the navigation by returning false or, navigate to your desired route by using router.push()
router.beforeEach(async (to, from)=> {
if(isAuth) {
router.push('/userPage')
}else {
return false
})
You can pass in an optional third argument called next
router.beforeEach(async (to, from)=> {
if(!isAuth) next({ name: 'Login' })
else next()
)
Global resolve guards are made to be accessed just before navigation is confirmed. Going by this logic, all route conditions and async functions are resolved before the global resolve guard is called. It is invoked using the router.beforeResolve()
router.beforeResolve(() => {
if(condition){
//do something
}else {
//do something else
}
})
Global after guards are accessed after each navigation is confirmed. From the vue-router docs, we are told that "They are useful for analytics, changing the title of the page, accessibility features like announcing the page and many other things."
router.afterEach((to, from) => {
//do something
})
You can also pass a third argument called failure to reflect navigation failures.
router.afterEach((to, from, failure) => {
//do something
})
Side Note: Vue router also provides a way to use injections in global guards.
router.beforeEach((to, from) => {
const startInjection = inject('injectionnn')
})
Per-Route Guards
This is the most used guard. It is used in a situation whereby each route logic is different from the rest or, only one particular route is needed to be protected.
It is defined inside a route using the beforeEach hook. The beforeEach hook a key separated from its value which is usually an arrow function
const routes = [
{
path: '/cart',
component: cart,
beforeEnter: (to, from) => {
// do something
return false
},
},
]
Alternatively, you could pass an array of functions as the value for beforeEnter
const function1 = () => {
//Something is done here
}
const function2 = () => {
//Something is done here
}
const routes = [
{
path: '/cart',
component: cart,
beforeEnter: [function1, function2]
},
]
In-Component Guards
As the name suggests, these are defined in a component. In composition API, two hooks are provided for this; onBeforeRouteLeave and onBeforeRouteUpdate.
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
onBeforeRouteLeave((to, from) => {
//do something
})
onBeforeRouteUpdate(async (to, from) => {
//do something else
})
Conclusion
As you have seen, vue-router provides out-of-the-box hooks designed to make your developer experience easier. We have talked about navigation guards and their different types. We have also seen that vue-router has made provisions for injections in a global route.
If you want to dig further, check the vue-router docs on navigation guards.
Subscribe to my newsletter
Read articles from Divine Udise directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by