Vue SDK
The @passkeybase/vue package provides a Vue 3 plugin, composables, and components for integrating passkey authentication into Vue applications.
Installation
npm install @passkeybase/vue @passkeybase/jsPlugin Setup
Register the plugin with app.use(). This initializes the SDK and makes auth state available to all components via Vue's provide/inject system.
import { createApp } from 'vue';
import { createPasskeyBase } from '@passkeybase/vue';
import App from './App.vue';
const app = createApp(App);
app.use(
createPasskeyBase({
clientId: 'pk_live_abc123',
domain: 'myapp.auth.ing',
redirectUri: window.location.origin + '/callback',
})
);
app.mount('#app');Auth Composables
useAuth()
Access reactive authentication state and methods. All returned values are Vue Refs that update automatically.
<script setup lang="ts">
import { useAuth } from '@passkeybase/vue';
const {
isAuthenticated,
isLoading,
loginWithRedirect,
logout,
getAccessToken,
} = useAuth();
async function fetchData() {
const token = await getAccessToken();
const res = await fetch('/api/data', {
headers: { Authorization: `Bearer ${token}` },
});
return res.json();
}
</script>
<template>
<div v-if="isLoading">Loading...</div>
<div v-else-if="!isAuthenticated">
<button @click="loginWithRedirect()">Log in with Passkey</button>
</div>
<div v-else>
<h1>Welcome back</h1>
<button @click="fetchData()">Fetch data</button>
<button @click="logout()">Log out</button>
</div>
</template>useUser()
Access the current user's profile as a reactive ref.
<script setup lang="ts">
import { useUser } from '@passkeybase/vue';
const { user, isLoading } = useUser();
</script>
<template>
<div v-if="isLoading">Loading profile...</div>
<div v-else-if="user">
<h2>{{ user.displayName }}</h2>
<p>{{ user.email }}</p>
<p>User ID: {{ user.sub }}</p>
<p>Passkeys registered: {{ user.credentials.length }}</p>
</div>
</template>Protected Routes
AuthGuard Component
Wrap any component tree that should only be visible to authenticated users. The fallback slot is shown while the auth state is being determined.
<script setup lang="ts">
import { AuthGuard } from '@passkeybase/vue';
</script>
<template>
<AuthGuard>
<!-- Only rendered when authenticated -->
<DashboardView />
<!-- Optional: shown while auth check is in progress -->
<template #fallback>
<div>Checking authentication...</div>
</template>
</AuthGuard>
</template>Vue Router Navigation Guard
Protect routes at the router level using a beforeEach guard. Mark routes with meta.requiresAuth.
import { createRouter, createWebHistory } from 'vue-router';
import { useAuth } from '@passkeybase/vue';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: () => import('./views/Home.vue') },
{ path: '/callback', component: () => import('./views/Callback.vue') },
{
path: '/dashboard',
component: () => import('./views/Dashboard.vue'),
meta: { requiresAuth: true },
},
{
path: '/settings',
component: () => import('./views/Settings.vue'),
meta: { requiresAuth: true },
},
],
});
router.beforeEach(async (to) => {
if (to.meta.requiresAuth) {
const { isAuthenticated, loginWithRedirect } = useAuth();
if (!isAuthenticated.value) {
await loginWithRedirect({ state: to.fullPath });
return false;
}
}
});
export default router;Login and Logout
Use the useAuth() composable for login and logout buttons, or build a custom UI.
<script setup lang="ts">
import { useAuth } from '@passkeybase/vue';
const { isAuthenticated, loginWithRedirect, logout } = useAuth();
function handleLogin() {
loginWithRedirect({
scopes: ['openid', 'profile', 'email'],
});
}
function handleLogout() {
logout({ returnTo: window.location.origin });
}
</script>
<template>
<nav>
<span>My App</span>
<button v-if="isAuthenticated" @click="handleLogout">Sign out</button>
<button v-else @click="handleLogin">Sign in with Passkey</button>
</nav>
</template>Handling the Callback
Create a callback page that calls handleRedirectCallback() and redirects the user into your app.
<script setup lang="ts">
import { onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { useAuth } from '@passkeybase/vue';
const { handleRedirectCallback } = useAuth();
const router = useRouter();
onMounted(async () => {
const result = await handleRedirectCallback();
const returnTo = result.state || '/dashboard';
router.push(returnTo);
});
</script>
<template>
<div>Completing login...</div>
</template>Passkey Enrollment
The useEnrollment() composable manages the passkey enrollment popup flow, including reactive loading and error state.
<script setup lang="ts">
import { useEnrollment, useAuth } from '@passkeybase/vue';
const { getAccessToken } = useAuth();
const { enrollPasskey, isEnrolling, error } = useEnrollment();
async function handleEnroll() {
// Fetch an enrollment token from your backend
const token = await getAccessToken();
const res = await fetch('/api/enrollment-token', {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
});
const { enrollmentToken } = await res.json();
// Open the enrollment popup
await enrollPasskey(enrollmentToken);
alert('Passkey added successfully!');
}
</script>
<template>
<div>
<h2>Passkey Management</h2>
<button @click="handleEnroll" :disabled="isEnrolling">
{{ isEnrolling ? 'Enrolling...' : 'Add a new passkey' }}
</button>
<p v-if="error" class="error">{{ error.message }}</p>
</div>
</template>TypeScript Support
All composables and components are fully typed. The plugin options, return types, and component props all ship with TypeScript definitions.
import type { User, AuthResult } from '@passkeybase/js';
import { useAuth, useUser } from '@passkeybase/vue';
// Composables return typed Refs
const { user } = useUser(); // Ref<User | undefined>
const { isAuthenticated } = useAuth(); // Ref<boolean>
// Plugin options are typed
import type { PasskeyBasePluginOptions } from '@passkeybase/vue';
const options: PasskeyBasePluginOptions = {
clientId: 'pk_live_abc123',
domain: 'myapp.auth.ing',
redirectUri: '/callback',
};Next steps
- JavaScript SDK -- core API reference
- Node.js SDK -- generate enrollment tokens on the server
- Enrollment Guide -- detailed enrollment flow walkthrough