Skip to main content

Vue

Official

Composables and plugins to add authentication to any Vue.js application.

Protecting Routes

~8 min

In a Vue app, routes define the paths within the application that users can navigate to, linking URLs to specific components. Securing routes is essential to protect sensitive data, prevent unauthorized access, and ensure that only authenticated users can access certain parts of the application. The ThunderID SDK provides multiple approaches to secure routes in your application. This guide demonstrates how to secure routes in a Vue 3 single-page app using the navigation guard helper shipped with `@thunderid/vue`.

Protecting Routes

If you prefer full control over how app routes are secured, you can build a custom solution using the primitives provided by the ThunderID Vue SDK. This helps when you need to run custom application logic before enabling or disabling a route.

1

Basic Custom Route Guard With `<SignedIn />`

The simplest approach is to wrap the protected page content with the `` component and render a fallback for unauthenticated users:

src/pages/Contact.vue
vue
<script setup>
</script>

<template>
  <SignedIn>
    <ContactDetails />
  </SignedIn>
  <SignedOut>
    <p>You must sign in to view this page.</p>
  </SignedOut>
</template>
2

Custom Composable Using `useThunderID`

For more advanced control, such as role-based protection or a redirect, use `useThunderID()` together with Vue Router's `useRouter`:

src/composables/useRequireAuth.ts
ts

export interface RequireAuthOptions {
  redirectTo?: string
  requireRole?: string
}

export function useRequireAuth(options: RequireAuthOptions = {}) {
  const { redirectTo = '/signin', requireRole } = options
  const { isInitialized, isSignedIn, user } = useThunderID()
  const router = useRouter()

  watchEffect(() => {
    if (!isInitialized.value) return

    if (!isSignedIn.value) {
      router.replace(redirectTo)
      return
    }

    if (requireRole && !user.value?.roles?.includes(requireRole)) {
      router.replace('/forbidden')
    }
  })
}
3

Custom Navigation Guard

You can also build a Vue Router navigation guard from scratch using the SDK's `inject` key directly. This is essentially what `createThunderIDGuard` does internally, and you can fork it to add custom logic.

src/router/guards.ts
ts

export const requireAuth: NavigationGuard = async (to, from, next) => {
  const ctx = inject<ThunderIDContext>(THUNDERID_KEY)

  if (!ctx) {
    return next({ path: '/signin' })
  }

  // Wait for initialization
  while (!ctx.isInitialized.value) {
    await new Promise((resolve) => requestAnimationFrame(resolve))
  }

  if (!ctx.isSignedIn.value) {
    return next({ path: '/signin', query: { redirect: to.fullPath } })
  }

  // Add any custom role / permission checks here

  return next()
}
1

`beforeEnter` Route Guard

Apply the guard to a single route using `beforeEnter`. This is the most common pattern when only a few routes need protection.

src/router/index.ts
ts

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/signin', component: SignIn },
    {
      path: '/dashboard',
      component: Dashboard,
      beforeEnter: createThunderIDGuard({ redirectTo: '/signin' }),
    },
    createCallbackRoute({ path: '/callback' }),
  ],
})

export default router
2

Global Guard with `router.beforeEach`

Apply the guard to every route at once using `router.beforeEach`. Combine this with per-route `meta` flags if you want to opt specific routes out of the check.

src/router/index.ts
ts

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home, meta: { public: true } },
    { path: '/signin', component: SignIn, meta: { public: true } },
    { path: '/dashboard', component: Dashboard },
  ],
})

const requireAuth = createThunderIDGuard({ redirectTo: '/signin' })

router.beforeEach((to, from, next) => {
  if (to.meta.public) {
    return next()
  }
  return requireAuth(to, from, next)
})

export default router
3

Customizing the Guard

The guard accepts the following options: | Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | `redirectTo` | `string` | `'/'` | Path to redirect unauthenticated users to | | `waitForInit` | `boolean` | `true` | Wait for the SDK to finish initializing before evaluating the auth state | | `initTimeout` | `number` | `10000` | Maximum time (in ms) to wait for SDK initialization before redirecting | For example, to reject immediately when the SDK is not yet initialized (without waiting):

src/router/index.ts
ts
const guard = createThunderIDGuard({
  redirectTo: '/signin',
  waitForInit: false,
})
4

Using the Callback Route Helper

`createCallbackRoute` returns a route record that renders the SDK's built-in `` component, which extracts OAuth parameters from the URL and finalises the sign-in.

src/router/index.ts
ts

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    createCallbackRoute({
      path: '/auth/callback',
      name: 'oauth-callback',
      onError: (error) => console.error('OAuth error:', error),
    }),
  ],
})
ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.