vue-oidc
v4.1.0
Published
A fully OAuth2.1 compliant vue library
Maintainers
Readme
Vue OAuth
vue-oidcis a fully OAuth 2.1 compliant vue library. The library supports all the 4 flows:
- resource
- implicit
- authorization code
- client credentials
Supports OIDC
PKCEsupport for authorization code with code verification
How to
Configure your oauth client
import { createOAuth } from 'vue-oidc'
const oauth = createOAuth({
config: {
issuerPath: 'https://accounts.google.com',
clientId: '<your_client_id>'
}
})
app = createApp(App)
app.use(oauth)- for oauth Authorization flow, add the oauth_callback to router
router.addRoute({
path: '/oauth_callback',
name: 'oauthCallback',
// a real (empty) component — a `() => null` lazy loader crashes the router's component
// resolution when the route actually renders (e.g. an SSR pass)
component: { render: () => null },
beforeEnter: oauthCallbackGuard
})where oauthCallbackGuard can be something like this:
import type { NavigationGuardWithThis, RouteLocationNormalized, RouteLocationRaw } from 'vue-router'
import { useOAuth } from 'vue-oidc'
export const oauthCallbackGuard: NavigationGuardWithThis<undefined> = async (to: RouteLocationNormalized) => {
const appId = 'app'
const { oauthCallback } = useOAuth()
await oauthCallback(`${appId}:${to.fullPath}`)
const { returnUrl } = to.query
return ((returnUrl && { path: returnUrl }) || { name: 'main', params: to.params }) as RouteLocationRaw
}Use oauth store
const oauth = useOAuth()- other miscellaneous stores:
useOAuthConfig(),useOAuthToken(),useOAuthUser(),useOAuthHttp()anduseOAuthInterceptors()
The composables resolve the current OAuth instance — via inject(oauthKey) inside component setup, and via
the last created/installed instance elsewhere (router guards, pinia stores). You can also hold on to the
instance returned by createOAuth() directly; it exposes everything the composables do
(token, user, status, login, checkToken, http, ...).
Override oauth functions (Optional)
Every network call (refresh, revoke, authorize, userInfo, ...) can be replaced per instance —
no mutation of shared objects:
import { createOAuth, defaultOAuthFunctions } from 'vue-oidc'
const oauth = createOAuth({
config: {...},
functions: {
refresh: async (token, config) => {
const result = await defaultOAuthFunctions.refresh(token, config)
// custom handling
return result
}
}
})SSR
Create and install one instance per request — instances are fully isolated (token, config, watchers).
dispose() stops an instance's watchers when the render is done.
Composables resolve the instance through Vue's injection context (app.use(oauth) provides it):
component setup, pinia store setups and vue-router navigation guards all run inside the app's
context, so they always answer with the request's instance. Outside any injection context the
module-level pointer (last created/installed instance) answers — on the server this throws
when several instances are alive, because a global answer could belong to another request:
// entry-server.ts — per request:
const oauth = createOAuth({ config: {...} })
app.use(oauth)
try {
return await renderToString(app)
} finally {
app.runWithContext(() => getActiveOAuth()).dispose()
}oauthCallback() no-ops on the server: the code_verifier lives in the browser's storage, and a
server-side exchange without it would still burn the single-use authorization code at the IDP —
the client's own exchange would then fail with invalid_grant. Callback guards need no SSR check.
The library itself never imports node:async_hooks — it stays runtime-agnostic.
Migrating from v3
- State moved from module scope onto the instance: multiple isolated instances are now possible and
SSR-safe. The composable API (
useOAuth(),useOAuthToken(), ...) is unchanged. - Overriding behavior by mutating
useOAuthFunctions()→ passfunctionstocreateOAuth()instead. - the instance type is
OAuth(v4'sOAuthInstancename is gone). - New exports:
oauthKey,defaultOAuthFunctions,isExpiredToken,getActiveOAuth. - v4's
setOAuthResolver/setActiveOAuthare gone — injection-context resolution covers guards and store setups, and ambiguous server-side pointer reads throw instead of guessing. - the
ignoredPathscomputed is gone: register interceptor exclusions with the idempotentignorePath(pattern), read them viaconfig.value.ignorePaths. login()resolves to the authorization url for the authorization-code flow — an SSR host can 302 to it; on the client the navigation already happened.- Stored tokens are compatible — same default
storageKey, same format.
Use Oauth functions (Optional)
import { inject } from 'vue'
const login = inject('login') //oauth login function
const logout = inject('logout') //oauth logout function
const http = inject('http') //axios http which will append authorization token
const oauthCallback = inject('oauth-callback') // if you want to call this from vue component not guardOAuth component
OAuth component is provided to quickly bootstrap oauth functionality
import OAuth from 'vue-oidc/component'
<OAuth response-type="code" :redirect-uri="redirectUri" :logout-redirect-uri="logoutRedirectUri" />if logout-redirect-uri is not used than token revoke endpoint will be used for logout
for oauth resource flow (default when no response-type is set) should be the following
<OAuth />To use the component correctly, make sure of the following:
import { createVuetify } from 'vuetify'
import { createI18n, useI18n } from 'vue-i18n'
import { createVueI18nAdapter } from 'vuetify/locale/adapters/vue-i18n'
const i18n = createI18n({
messages: {
en: {
oauth: {
login: 'Login',
logout: 'Logout',
username: 'Username',
password: 'Password',
usernameRequired: 'Name is required',
passwordRequired: 'Password is required',
usernameLength: 'Name must be less than {0} characters',
passwordLength: 'Password must be less than {0} characters'
}
}
},
})
app.use(i18n).use(createVuetify({
locale: {
adapter: createVueI18nAdapter({ i18n, useI18n } as any)
}
}))Sample configs
Keycloak example for oidc with autodiscovery
const keycloakOpenIDConfig = {
config: {
issuerPath: 'http://localhost:8080/realms/<some-realm>',
clientId: '<your_client_id>',
}
};Azure example
const azureOpenIDConfig = {
config: {
issuerPath: 'https://login.microsoftonline.com/common/v2.0', // for common make sure you app has "signInAudience": "AzureADandPersonalMicrosoftAccount",
clientId: '<your_client_id>',
scope: 'openid profile email offline_access',
pkce: true // manually, since is required, but code_challenge_methods_supported is not in openid configuration
}
}Google example
const googleOpenIDConfig = {
config: {
issuerPath: 'https://accounts.google.com',
clientId: '<your_client_id>',
clientSecret: '<your_client_secret>',
scope: 'openid profile email'
}
}Installing:
bun i vue-oidc --saveApp Requirements
- vue3
- vuetify/vue-i18n if using the
OAuthcomponent
