@wocha/vue
| Install | |
|---|---|
npm install @wocha/vue |
|
| Latest Version: | 0.2.0 |
| Vue: | 3 |
| License: | Apache-2.0 |
| Last Updated: | Sep 29, 2026 |
| Links: | npm |
@wocha/vue
Vue 3 composables and headless components for Wocha authentication in single-page applications. Implements the OAuth 2.0 authorisation code flow with PKCE as a public client — no client secret required.
Install
npm install @wocha/vue
# or: pnpm add / yarn add / bun add @wocha/vue
Peer dependency: Vue 3.4+.
Quick start
Install the plugin in your app entry point and register a /callback route for the OAuth redirect:
// main.ts
import { createApp } from "vue";
import { GreetPlugin } from "@wocha/vue";
import App from "./App.vue";
const app = createApp(App);
app.use(GreetPlugin, {
config: {
issuer: "https://my-tenant.auth.wocha.ai",
clientId: "your-client-id",
redirectUri: window.location.origin + "/callback",
},
});
app.mount("#app");
Register your redirect URI (https://your-app.com/callback) in the Wocha Console before testing.
Configuration reference
Pass a WochaAuthConfig object to GreetPlugin:
| Field | Type | Required | Description |
|---|---|---|---|
issuer |
string |
Yes | OIDC issuer URL (e.g. https://my-tenant.auth.wocha.ai). |
clientId |
string |
Yes | OAuth client ID for your SPA application. |
redirectUri |
string |
Yes | Callback URL registered with your OAuth client. |
scope |
string |
No | Space-separated scopes. Default: openid profile email org_id offline_access. |
audience |
string |
No | API audience claim, if your tenant requires it. |
apiUrl |
string |
No | Customer API base URL for permission checks. Defaults to {tenant}.api.wocha.ai/v1 on Wocha Cloud. |
storage |
"session" | "local" |
No | Where refresh tokens are persisted. Default: session. |
onRedirectCallback |
(appState?: unknown) => void |
No | Called after a successful OAuth callback. |
Composables
All composables must be used after app.use(GreetPlugin, …).
useSession()
Reactive session state with loading, authenticated, and unauthenticated statuses:
<script setup lang="ts">
import { useSession } from "@wocha/vue";
const { data, status, error, refresh } = useSession();
</script>
<template>
<p v-if="status === 'loading'">Loading…</p>
<p v-else-if="status === 'authenticated'">Hello, {{ data?.email }}</p>
<p v-else>Please sign in</p>
</template>
useUser()
Returns the current user and auth status:
const { user, status } = useUser();
useOrg()
Organisation context with switchOrg():
<script setup lang="ts">
import { useOrg } from "@wocha/vue";
const { orgId, orgIds, switchOrg, isSwitching } = useOrg();
</script>
<template>
<select
:value="orgId"
:disabled="isSwitching"
@change="switchOrg(($event.target as HTMLSelectElement).value)"
>
<option v-for="id in orgIds" :key="id" :value="id">{{ id }}</option>
</select>
</template>
Some org switches require re-authorisation; switchOrg handles the redirect automatically when needed.
usePermission(check)
SpiceDB permission check against the Customer API:
<script setup lang="ts">
import { usePermission } from "@wocha/vue";
const { allowed, isLoading } = usePermission({
resource: { type: "document", id: "doc-123" },
permission: "edit",
});
</script>
<template>
<button v-if="allowed && !isLoading">Edit</button>
</template>
useWochaAuth()
Imperative auth actions:
const { signIn, signOut, switchOrg, getAccessToken, isAuthenticated, isLoading } = useWochaAuth();
await signIn({ appState: { returnTo: "/dashboard" } });
await signIn({ signup: true });
signOut();
login and logout are aliases for signIn and signOut.
Components
Headless components using slots:
<template>
<Authenticated>
<Dashboard />
</Authenticated>
<Unauthenticated>
<SignInPrompt />
</Unauthenticated>
<Protect
:permission="{ resource: { type: 'document', id: docId }, permission: 'edit' }"
>
<EditForm />
</Protect>
</template>
<script setup lang="ts">
import { Authenticated, Unauthenticated, Protect } from "@wocha/vue";
</script>
Also available: SignIn, SignUp, and OrgSwitcher with optional scoped slots.
Security model
- Public client (PKCE): No client secret in the browser. Suitable for SPAs only.
- Token storage: Refresh tokens use
sessionStorageby default (cleared when the tab closes). Access tokens are kept in memory and refreshed automatically. - Multi-tab sync: Login, logout, and org switches broadcast across tabs via
BroadcastChannel. - No server-side session: Use
@wocha/sveltekitor@wocha/nextjsfor BFF patterns with httpOnly cookies.
Environment variables
Vite requires VITE_-prefixed variables (VITE_WOCHA_ISSUER, VITE_WOCHA_CLIENT_ID). Values are baked in at build time — restart the dev server after changing .env.
Related packages
| Package | Use when |
|---|---|
@wocha/sveltekit |
SvelteKit with server-side sessions |
@wocha/nextjs |
Next.js App Router with server-side sessions |
@wocha/react |
React SPA with the same PKCE flow |
@wocha/sdk |
Server-side user/org management via the Management API |
Troubleshooting
redirect_uri_mismatch
The redirectUri must exactly match a redirect URI registered in the Wocha Console.
CSRF / state_mismatch
Clear site storage for your origin and retry. Do not start a second login flow before the first completes.
CORS errors
Confirm the OAuth application allows your SPA origin for browser-based token requests.
Related Packages
A comprehensive authentication integration for Vue applications with TypeScript...
Nuxt 4 module for OIDC/SSO authentication with Laravel Passport or any OIDC prov...
A comprehensive authentication integration for Nuxt 4 applications with TypeScri...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.2.0 | ^3.4.0 | Apache-2.0 | |
| 0.1.0 | ^3.4.0 | Apache-2.0 |