Skip to main content

Custom Implementation

If you prefer to have full control over how the app routes should be secured—for example, if you want to run custom application logic before enabling or disabling a route—you can build a completely custom solution using the primitives provided by the ThunderID Vue SDK.

Basic Custom Route Guard With <SignedIn />

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

src/pages/Contact.vue
<script setup>
import { SignedIn, SignedOut } from '@thunderid/vue'
import ContactDetails from '../components/ContactDetails.vue'
</script>

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

Custom Composable Using useThunderID

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

src/composables/useRequireAuth.ts
import { watchEffect } from 'vue'
import { useRouter } from 'vue-router'
import { useThunderID } from '@thunderid/vue'

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')
}
})
}

Then use it inside any protected page:

src/pages/AdminDashboard.vue
<script setup>
import { useRequireAuth } from '../composables/useRequireAuth'

useRequireAuth({ redirectTo: '/signin', requireRole: 'admin' })
</script>

<template>
<h1>Admin Dashboard</h1>
<!-- ... -->
</template>

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
import { inject } from 'vue'
import type { NavigationGuard } from 'vue-router'
import { THUNDERID_KEY } from '@thunderid/vue'
import type { ThunderIDContext } from '@thunderid/vue'

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()
}
ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© WSO2 LLC. All rights reserved.