agentsclimarketplace

Volverjs auth vue

Skill volverjs/auth-vue/skills/volverjs-auth-vue

Integrate OAuth2 / OpenID Connect authentication into a Vue 3 app with @volverjs/auth-vue. Use when adding login/logout, the authorization-code + PKCE flow, token refresh, an access token for API calls, route guards, or reactive auth state (loggedIn/accessToken) to a Vue 3 application.From its SKILL.md

Install
npx -y skills add volverjs/auth-vue --skill volverjs-auth-vue

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 11 stars11 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.3 KB, as published. Nobody here has run it

@volverjs/auth-vue is a thin, reactive Vue 3 wrapper around oauth4webapi for the OAuth 2.0 Authorization Code flow with PKCE (and OpenID Connect). It runs in the browser only and gives you reactive loggedIn / accessToken state, automatic token persistence, refresh, and logout.

Use this skill to wire it into a consuming Vue app. It does not require running this repo — it's reference for integrating the published package.

Install

pnpm add @volverjs/auth-vue   # peer dependency: vue ^3.5

Mental model

  • One client holds all config and reactive state. Create it once.
  • initialize() is the entry point you call on app start. After OAuth-server discovery it automatically:
    1. completes login if a ?code=... is present in the URL (returning from the IdP),
    2. otherwise refreshes the access token if a refresh token is stored,
    3. otherwise stays logged out.
  • authorize() sends the user to the IdP to log in. logout() sends them to the IdP to log out.
  • The refresh token, code verifier and state/nonce are persisted to localStorage by default (scoped under an oauth. key prefix).

Setup as a Vue plugin (recommended)

main.ts:

import { createOAuthClient } from '@volverjs/auth-vue'
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

const auth = createOAuthClient({
    url: 'https://my-idp.example.com', // OAuth issuer (must expose /.well-known/openid-configuration)
    clientId: 'my-spa-client-id',
    scopes: 'openid profile email offline_access', // offline_access → get a refresh token
    redirectUri: `${location.origin}/callback`, // must be registered at the IdP
    postLogoutRedirectUri: location.origin,
})

// Discovery + auto-complete login if returning from the IdP, before mount.
await auth.initialize()

app.use(auth, { global: true }) // { global: true } also exposes this.$vvAuth in Options API
app.mount('#app')

Then in any component get the client with the composable:

<script setup lang="ts">
import { useOAuthClient } from '@volverjs/auth-vue'

const auth = useOAuthClient() // must be called inside setup()
// auth.loggedIn  → ComputedRef<boolean>
// auth.accessToken → readonly Ref<string | undefined>
</script>

<template>
    <button v-if="!auth.loggedIn.value" @click="auth.authorize()">
        Login
    </button>
    <button v-else @click="auth.logout()">
        Logout
    </button>
</template>

Setup as a standalone instance (no plugin)

import { OAuthClient } from '@volverjs/auth-vue'

export const auth = new OAuthClient({
    url: 'https://my-idp.example.com',
    clientId: 'my-spa-client-id',
    scopes: ['openid', 'profile'],
})

await auth.initialize()
// import { auth } wherever you need it; loggedIn/accessToken are reactive.

The login round-trip

  1. User clicks Login → auth.authorize() → browser redirects to the IdP (with PKCE code_challenge, state, and nonce when openid is requested).
  2. IdP redirects back to redirectUri with ?code=...&state=....
  3. On that page, auth.initialize() sees the code and completes the exchange automatically — loggedIn flips to true and accessToken is populated.

If you handle the callback on a dedicated route and want to do it explicitly:

import { useOAuthClient } from '@volverjs/auth-vue'

const auth = useOAuthClient()
await auth.initialize() // discovery
await auth.handleCodeResponse(new URLSearchParams(location.search))
// then router.replace('/') to drop the ?code=... from the URL

API reference

Core members used above: await initialize() (discovery + auto login/refresh), await authorize(), await handleCodeResponse(params), await refreshToken(), logout(hint?), plus reactive loggedIn / accessToken and the initialized flag. useOAuthClient(options?) returns the installed client inside setup().

For the full option table, method signatures and the confidential-client auth helpers, read references/api.md.

Common patterns

Attach the access token to API requests (reactive — re-reads the current token):

import { useOAuthClient } from '@volverjs/auth-vue'

export function useApi() {
    const auth = useOAuthClient()
    return (input: RequestInfo, init: RequestInit = {}) =>
        fetch(input, {
            ...init,
            headers: {
                ...init.headers,
                ...(auth.accessToken.value
                    ? { Authorization: `Bearer ${auth.accessToken.value}` }
                    : {}),
            },
        })
}

Vue Router guard — require login, kicking off authorize() when needed:

router.beforeEach((to) => {
    const auth = oauthClient // your singleton or app-level client
    if (to.meta.requiresAuth && !auth.loggedIn.value) {
        auth.authorize() // redirects to the IdP
        return false
    }
})

For a browser SPA, leave clientAuthentication unset (the default is a public client) and rely on PKCE — never ship a client secret to the browser. Confidential clients with a secret set clientAuthentication with a helper; see references/api.md.

Storage & security

  • Default is localStorage, which survives restarts and is readable by any JS on the origin (a single XSS exposes the refresh token). Prefer storageType: 'session' when you don't need persistent, cross-tab sessions, or pass a custom storage.
  • PKCE (S256) and a random state (CSRF protection) are always used; a nonce (OIDC replay protection) is added and validated only when the openid scope is requested.
  • Keys are scoped under the storage base key (default oauth.), so multiple instances don't collide.

Gotchas

  • Browser-only (SSR/Nuxt): the client touches document/window/Web Storage. Construction is SSR-safe, but call initialize()/authorize() on the client (e.g. onMounted, a client-only plugin, or guarded by import.meta.client).
  • No refresh token? Add the offline_access scope (or the IdP's equivalent) — otherwise initialize() can't restore a session after reload and the user must log in again.
  • openid requires an id_token: when the openid scope is set, the token response must include a (signed) id_token or the exchange fails. Standard IdPs do this; bare OAuth2 servers may not — drop openid for pure OAuth2.
  • redirectUri mismatch is the most common setup error: it must exactly match what's registered at the IdP.
  • Clean the URL after login: ?code=...&state=... stays in the address bar after initialize() completes the exchange; router.replace(location.pathname) to remove it.
  • Reactivity: in <script> use auth.loggedIn.value / auth.accessToken.value; in <template> they auto-unwrap.

Migrating from 0.0.x

Upgrading an existing integration? The breaking change is tokenEndpointAuthMethod (a string) → clientAuthentication (a helper). Full mapping and other changes (oauth4webapi 3.x, Node ≥ 20, state/nonce) in references/migration.md.

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.