@wocha/vue

Vue 3 composables and components for Wocha authentication (PKCE SPA flow)
393
Install
npm install @wocha/vue
Latest Version:0.2.0
Vue:3
License:Apache-2.0
Last Updated:Sep 29, 2026
Links: npm
Maintainer: augusta_king

@wocha/vue

npm version npm downloads TypeScript License

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 sessionStorage by 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/sveltekit or @wocha/nextjs for 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

@wocha/nuxt

Nuxt 3 module for Wocha authentication (BFF pattern with httpOnly cookies)

599
@zitadel/vue-auth

A comprehensive authentication integration for Vue applications with TypeScript...

2,151 27
@mbsoftlabs/nuxt-oidc-auth

Nuxt 4 module for OIDC/SSO authentication with Laravel Passport or any OIDC prov...

4,296 0
@zitadel/nuxt-auth

A comprehensive authentication integration for Nuxt 4 applications with TypeScri...

1,627 1
casdoor-vue-sdk

Vue client SDK for Casdoor

21,991 16

Version History

Version Released Vue License
0.2.0 ^3.4.0 Apache-2.0
0.1.0 ^3.4.0 Apache-2.0