oidc-login-plugin
v2.5.0
Published
A configurable Vue 3 plugin that adds router guards, axios interceptors, and pinia integration.
Maintainers
Readme
OIDC Login Plugin for Vue 3
A configurable Vue 3 plugin that provides OIDC authentication with router guards, axios interceptors, and Pinia integration.
Installation
npm install oidc-login-plugin
# or
pnpm add oidc-login-pluginIntegration Modes
The plugin supports three integration modes depending on your auth architecture:
| Mode | Use case | Setup |
|------|----------|-------|
| Full | OIDC-only SPA | Pass router + axios to app.use(OidcPlugin, …) |
| Core | Pinia/UserManager only | Pass pinia + oidc only — no router/axios warnings |
| Composable | Dual-auth / custom guards | Core install + import helpers and hooks |
Full mode (default)
OIDC-only apps — same behavior as before:
app.use(OidcPlugin, {
pinia,
router,
axios: axiosInstance,
oidc: { /* ... */ },
});Core mode
Use only the Pinia UserManager layer. No router guards or axios interceptor are registered:
app.use(OidcPlugin, {
pinia,
oidc: { /* ... */ },
// router and axios omitted intentionally — no warnings
});Handle the OIDC callback manually with createOidcCallbackHandler or the OidcCallback component.
Composable mode (dual-auth)
For apps that mix OIDC (e.g. staff) with another auth system (e.g. customer JWT), install in Core mode and wire integrations yourself with hooks:
import {
OidcPlugin,
setupOidcRouterGuards,
setupOidcAxiosInterceptor,
} from 'oidc-login-plugin';
// Core install — no global OIDC enforcement
app.use(OidcPlugin, { pinia, oidc: { /* ... */ } });
// Only apply OIDC guards when the session is OIDC
setupOidcRouterGuards(router, {
redirectUri: oidc.userManagerSettings.redirect_uri,
hooks: {
shouldHandleRoute: (to) =>
to.meta.authMode === 'oidc' || isIdentityJwt(getToken()),
},
});
// Only refresh OIDC tokens on 401 for OIDC sessions
setupOidcAxiosInterceptor(axiosInstance, {
hooks: {
shouldHandleUnauthorized: () => isIdentityJwt(getAuthToken()),
},
});You can also disable built-in integrations while still passing instances for manual setup:
app.use(OidcPlugin, {
pinia,
router,
axios: axiosInstance,
oidc: { /* ... */ },
features: {
router: false,
axios: false,
},
});Quick Start
1. Create your router
import { createRouter } from 'vue-router';
const router = createRouter({
routes: [
{
path: '/dashboard',
component: Dashboard,
meta: { requiresAuth: true }
}
]
});2. Install the plugin
Important: Use this plugin BEFORE app.use(router) because it modifies the router by adding guards and routes.
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import axios from 'axios';
import OidcPlugin from 'oidc-login-plugin';
import router from './router';
import App from './App.vue';
const app = createApp(App);
const pinia = createPinia();
const axiosInstance = axios.create({
baseURL: 'https://api.example.com'
});
// Install Pinia first
app.use(pinia);
// Install OIDC plugin BEFORE router
app.use(OidcPlugin, {
pinia,
router,
axios: axiosInstance,
oidc: {
userManagerSettings: {
authority: 'https://your-idp.com',
client_id: 'your-client-id',
redirect_uri: 'http://localhost:3000/callback',
post_logout_redirect_uri: 'http://localhost:3000',
response_type: 'code',
scope: 'openid profile email',
},
storageKey: 'authToken',
redirectUrl: '/login'
},
identityAppsUrl: 'https://your-idp.com/apps',
debug: true
});
// Install router AFTER the plugin
app.use(router);
app.mount('#app');3. Use the store and composables
import { useUserStore, useGlobal } from 'oidc-login-plugin';
// User store for authentication state
const userStore = useUserStore();
const isAuth = await userStore.isAuthenticated();
const user = userStore.user;
// Global composable for logout with redirect
const { logout } = useGlobal();
logout(); // Logs out and redirects to identityAppsUrlImportant Notes
⚠️ Plugin Installation Order: Always use app.use(OidcPlugin, ...) BEFORE app.use(router) because the plugin modifies the router by:
- Adding the callback route dynamically based on your
redirect_uri - Setting up navigation guards for protected routes
- Configuring authentication flow
// ✅ Correct order
app.use(pinia);
app.use(OidcPlugin, { ... });
app.use(router);
// ❌ Wrong order - guards and routes won't work properly
app.use(router);
app.use(OidcPlugin, { ... });Features
- ✅ OIDC authentication with oidc-client-ts
- ✅ Three integration modes: Full, Core, Composable
- ✅ Opt-in router guards and axios interceptor via
featuresflags - ✅ Customization hooks for dual-auth (
shouldHandleRoute,shouldHandleUnauthorized, …) - ✅ Tree-shakeable named exports (
setupOidcRouterGuards,createOidcCallbackHandler, …) - ✅ Automatic callback route registration (no manual route needed)
- ✅ Built-in callback component with loading UI
- ✅ Router guards for protected routes (
meta: { requiresAuth: true }) - ✅ Axios interceptor with automatic token refresh on 401
- ✅ Pinia store for user state management
- ✅ Global logout with configurable redirect
- ✅ Configurable storage keys and redirect URLs
- ✅ Debug mode for development
- ✅ TypeScript support
How It Works
The plugin automatically:
- Registers a callback route - Dynamically adds the callback route based on your
redirect_uriconfiguration - Sets up router guards - Protects routes with
meta: { requiresAuth: true }and redirects unauthenticated users to OIDC sign-in - Configures axios interceptor - Adds Bearer token to requests and handles 401 errors with automatic token refresh
- Initializes user store - Creates a Pinia store with user state, authentication methods, and UserManager instance
Composable API
Named exports for manual integration:
import {
useUserStore,
setupOidcRouterGuards,
setupOidcAxiosInterceptor,
createOidcCallbackHandler,
resolveOidcReturnUrl,
installSigninSilentDedupe,
OidcCallback,
} from 'oidc-login-plugin';Hooks
type OidcIntegrationHooks = {
/** Return false to skip OIDC handling (dual-auth). */
shouldHandleRoute?: (to) => boolean | Promise<boolean>;
/** Return false to skip OIDC refresh on 401. */
shouldHandleUnauthorized?: (error) => boolean | Promise<boolean>;
/** Custom redirect when auth fails instead of signinRedirect. */
onUnauthenticated?: (ctx: { route?; error? }) => void | Promise<void>;
/** Called after successful token refresh. */
onTokenRefreshed?: (user) => void | Promise<void>;
/** Choose which token to persist (access_token vs id_token). */
selectAccessToken?: (user) => string | null;
};Pass hooks globally via app.use(OidcPlugin, { hooks }) or per-integration via setupOidcRouterGuards(router, { hooks }).
Documentation
See USAGE.md for detailed documentation.
License
ISC
