vuethenticate
v0.1.13
Published
A Vue 3 authentication state management library using oidc-client-ts
Downloads
316
Maintainers
Readme
Vuethenticate
A Vue 3 authentication state management library using oidc-client-ts.
Features
- 🔐 OIDC/OAuth2 authentication with automatic token management
- ⚡ Vue 3 Composition API with reactive state
- 🔄 Automatic token renewal
- 📦 TypeScript support
- 🎯 Minimal configuration required
- 🎨 Customizable callback component
Installation
npm install vuethenticateQuick Start
Important Setup Order: Make sure to initialize
useAuth()in your main App component or a parent component before any callback routes are accessible. The callback components depend on this initialization.
1. Configure Authentication
<!-- App.vue - Main Application Component -->
<script setup>
import { useAuth } from 'vuethenticate'
import { RouterView } from 'vue-router'
// Initialize authentication in your main app component
const { user, isAuthenticated, signIn, signOut } = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id'
})
</script>
<template>
<div id="app">
<nav>
<div v-if="isAuthenticated">
<p>Welcome, {{ user.profile.name }}!</p>
<button @click="signOut">Sign Out</button>
</div>
<div v-else>
<button @click="signIn">Sign In</button>
</div>
</nav>
<!-- Router outlet - callback routes will work properly now -->
<RouterView />
</div>
</template>2. Setup Callback Route
<!-- CallbackPage.vue -->
<script setup>
import { AuthCallback } from 'vuethenticate'
function onSuccess(user, state) {
console.log('Authentication successful:', user)
console.log('State:', state)
// Redirect to app or show success message
window.location.href = '/dashboard'
}
function onError(error) {
console.error('Authentication failed:', error)
// Handle error - redirect to login or show error
window.location.href = '/login'
}
</script>
<template>
<AuthCallback
:onSuccess="onSuccess"
:onError="onError"
>
<div>Signing you in...</div>
<template #error="{ error }">
<div>
<h2>Authentication Failed</h2>
<p>{{ error.message }}</p>
</div>
</template>
</AuthCallback>
</template>3. Add Route Configuration
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import CallbackPage from './CallbackPage.vue'
import LogoutCallbackPage from './LogoutCallbackPage.vue'
import SilentCallbackPage from './SilentCallbackPage.vue'
const routes = [
{
path: '/auth/callback',
component: CallbackPage
},
{
path: '/auth/logout-callback',
component: LogoutCallbackPage
},
{
path: '/auth/silent-callback',
component: SilentCallbackPage
},
// ... other routes
]
export default createRouter({
history: createWebHistory(),
routes
})4. Setup Silent Callback (for Token Renewal)
<!-- SilentCallbackPage.vue -->
<script setup>
import { SilentCallback } from 'vuethenticate'
function onError(error) {
console.error('Silent renewal failed:', error)
}
</script>
<template>
<SilentCallback :onError="onError" />
</template>URL State Support
You can pass state through the authentication flow with full TypeScript support:
// Define your state type
interface MyAppState {
returnUrl: string;
theme: 'light' | 'dark';
userId?: string;
}
// Use with generic type parameter
const auth = useAuth<MyAppState>(config);
// Pass state during sign in
await auth.signIn({
returnUrl: '/dashboard',
theme: 'dark'
});
// Pass state during sign out
await auth.signOut({
returnUrl: '/goodbye',
theme: 'light'
});Receiving State in Callback
<script setup lang="ts">
import { AuthCallback } from 'vuethenticate';
interface MyAppState {
returnUrl: string;
theme: 'light' | 'dark';
}
const handleSuccess = (user: User, state?: MyAppState) => {
if (state?.returnUrl) {
router.push(state.returnUrl);
}
if (state?.theme) {
setTheme(state.theme);
}
};
</script>
<template>
<AuthCallback<MyAppState>
@success="handleSuccess"
/>
</template>Important: Make sure to call
useAuth()in your main App component or a parent component before rendering any callback components. The callback components rely on the authentication being initialized first.
API Reference
useAuth(config)
The main composable for authentication state management.
Configuration
| Property | Type | Required | Default | Description |
|----------|------|----------|---------|-------------|
| authority | string | ✓ | - | OIDC provider URL |
| clientId | string | ✓ | - | Application client ID |
| redirectUri | string | | ${origin}/auth/callback | Callback URL |
| scope | string | | 'openid profile' | OIDC scopes |
| responseType | string | | 'code' | OAuth response type |
| storage | 'localStorage' \| 'sessionStorage' \| 'memory' | | 'localStorage' | Storage type |
| automaticSilentRenew | boolean | | true | Enable automatic token refresh |
| silentRedirectUri | string | | ${origin}/auth/silent-callback | Silent refresh callback URL |
| postLogoutRedirectUri | string | | ${origin} | Post-logout redirect URL |
| logLevel | LogLevel | | LogLevel.NONE | Logging level for debug information |
| logger | Logger | | silentLogger | Custom logger implementation |
Event Callbacks
| Property | Type | Description |
|----------|------|-------------|
| onError | (error: Error) => void | Called when an error occurs |
| onUserLoaded | (user: User) => void | Called when user is loaded |
| onUserUnloaded | () => void | Called when user is unloaded |
| onAccessTokenExpired | () => void | Called when access token expires |
| onAccessTokenExpiring | () => void | Called before access token expires |
| onSilentRenewError | (error: Error) => void | Called when silent token renewal fails (auth state is automatically reset) |
Returns
| Property | Type | Description |
|----------|------|-------------|
| user | Ref<User \| null> | Current user object |
| isAuthenticated | Ref<boolean> | Authentication status |
| isLoading | Ref<boolean> | Loading state |
| error | Ref<Error \| null> | Current error |
| accessToken | Ref<string \| null> | Current access token |
| isExpired | Ref<boolean> | Token expiration status |
| signIn | (state?: TState) => Promise<void> | Initiate sign in with optional state |
| signOut | (state?: TState) => Promise<void> | Sign out user with optional state |
| silentRenew | () => Promise<void> | Manually renew token |
| clearError | () => void | Clear current error |
| resetAuthState | () => Promise<void> | Manually reset authentication state by removing user and clearing reactive state |
| cleanup | () => void | Manual cleanup of UserManager resources (rarely needed) |
<AuthCallback>
Component for handling OAuth callback. Note: This component requires useAuth() to be called in a parent component first.
Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| onSuccess | (user: User, state?: TState) => void | | Success callback with typed state |
| onError | (error: Error) => void | | Error callback |
Slots
| Slot | Props | Description |
|------|-------|-------------|
| default | - | Loading content |
| error | { error: Error } | Error content |
Events
| Event | Payload | Description |
|-------|---------|-------------|
| success | User, state?: TState | Emitted on successful authentication with typed state |
| error | Error | Emitted on authentication error |
<LogoutCallback>
Component for handling OAuth logout callback. Note: This component requires useAuth() to be called in a parent component first.
Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| onSuccess | (state?: TState) => void | | Success callback with typed state |
| onError | (error: Error) => void | | Error callback |
Slots
| Slot | Props | Description |
|------|-------|-------------|
| default | - | Loading content |
| error | { error: Error } | Error content |
| success | - | Success content |
Events
| Event | Payload | Description |
|-------|---------|-------------|
| success | state?: TState | Emitted on successful logout with typed state |
| error | Error | Emitted on logout error |
Usage
<!-- LogoutCallbackPage.vue -->
<script setup>
import { LogoutCallback } from 'vuethenticate'
function onSuccess(state) {
console.log('Logout successful:', state)
// Redirect to home or show success message
window.location.href = '/'
}
function onError(error) {
console.error('Logout failed:', error)
// Handle error - redirect or show error
window.location.href = '/error'
}
</script>
<template>
<LogoutCallback
:onSuccess="onSuccess"
:onError="onError"
>
<div>Processing logout...</div>
<template #error="{ error }">
<div>
<h2>Logout Failed</h2>
<p>{{ error.message }}</p>
</div>
</template>
<template #success>
<div>
<h2>Logout Successful</h2>
<p>You have been logged out successfully.</p>
</div>
</template>
</LogoutCallback>
</template><SilentCallback>
Component for handling silent token renewal callbacks. This component should be mounted on a separate route (typically /auth/silent-callback) and is used internally by the library for automatic token refresh. Note: This component requires useAuth() to be called in a parent component first.
Props
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| onError | (error: Error) => void | | Error callback for silent renewal failures |
Usage
<template>
<SilentCallback :onError="handleSilentError" />
</template>
<script setup>
import { SilentCallback } from 'vuethenticate'
function handleSilentError(error) {
console.error('Silent renewal failed:', error)
}
</script>Note: This component is primarily used in an iframe or popup for silent token renewal. It should be placed on a minimal page with no other content.
Logging and Debugging
Vuethenticate provides comprehensive logging capabilities to help debug authentication flows and monitor authentication events. The logging system supports both internal library logging and configurable oidc-client-ts debug output.
Log Levels
import { LogLevel } from 'vuethenticate';
enum LogLevel {
NONE = 0, // No logging
ERROR = 1, // Only errors
WARN = 2, // Warnings and errors
INFO = 3, // Info, warnings, and errors
DEBUG = 4, // All messages including debug info
}Basic Logging Setup
import { useAuth, LogLevel, consoleLogger } from 'vuethenticate';
// Enable debug logging with console output
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
logLevel: LogLevel.DEBUG,
logger: consoleLogger
});Custom Logger Implementation
import { useAuth, LogLevel, type Logger } from 'vuethenticate';
const customLogger: Logger = {
error: (message: string, ...args: unknown[]) => {
// Send to your error tracking service
console.error('[AUTH ERROR]', message, ...args);
// Sentry.captureException(new Error(message));
},
warn: (message: string, ...args: unknown[]) => {
console.warn('[AUTH WARN]', message, ...args);
},
info: (message: string, ...args: unknown[]) => {
console.info('[AUTH INFO]', message, ...args);
},
debug: (message: string, ...args: unknown[]) => {
if (process.env.NODE_ENV === 'development') {
console.debug('[AUTH DEBUG]', message, ...args);
}
},
};
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
logLevel: LogLevel.INFO,
logger: customLogger
});Environment-Based Logging
import { useAuth, LogLevel, consoleLogger } from 'vuethenticate';
const getLogConfig = () => {
switch (process.env.NODE_ENV) {
case 'development':
return { logLevel: LogLevel.DEBUG, logger: consoleLogger };
case 'test':
return { logLevel: LogLevel.NONE };
case 'production':
return { logLevel: LogLevel.ERROR, logger: productionLogger };
default:
return { logLevel: LogLevel.WARN, logger: consoleLogger };
}
};
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
...getLogConfig()
});Available Loggers
consoleLogger
Standard console output logger suitable for development.
silentLogger
No-op logger that suppresses all output (default when no logger is specified).
createLevelLogger(baseLogger, level)
Creates a filtered logger that only outputs messages at or above the specified level.
import { createLevelLogger, consoleLogger, LogLevel } from 'vuethenticate';
const warnOnlyLogger = createLevelLogger(consoleLogger, LogLevel.WARN);What Gets Logged
When logging is enabled, you'll see output for:
- Authentication initialization - Setup and configuration validation
- Token operations - Token acquisition, renewal, and expiration
- User state changes - Login, logout, and user profile updates
- Silent renewal - Background token refresh attempts
- OIDC protocol flows - Detailed protocol-level debugging (when DEBUG level)
- Error conditions - All authentication-related errors with context
OIDC Client Debug Logs
The underlying oidc-client-ts library has extensive debug logging. When you configure logging in Vuethenticate, it automatically configures the OIDC client logging as well, so you'll see detailed protocol-level information including:
- HTTP requests and responses
- Token validation steps
- Silent renewal iframe operations
- OIDC discovery document processing
Production Considerations
For production environments, consider:
- Setting
logLeveltoLogLevel.ERRORorLogLevel.NONE - Using a custom logger that sends errors to your monitoring service
- Avoiding debug-level logging to prevent performance impact
- Implementing log sampling for high-traffic applications
// Production-safe logging configuration
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
logLevel: LogLevel.ERROR,
logger: {
error: (message, ...args) => {
// Send to monitoring service
monitoringService.error(message, args);
},
warn: () => {}, // Suppress in production
info: () => {}, // Suppress in production
debug: () => {}, // Suppress in production
}
});Logging
Vuethenticate provides comprehensive logging support for debugging authentication flows and OIDC protocol interactions. Logging is silent by default - you must explicitly configure it to see output.
Configuration
Add logging configuration to your auth config:
import { useAuth, LogLevel, consoleLogger } from 'vuethenticate'
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
// Enable debug logging
logLevel: LogLevel.DEBUG,
// logger: consoleLogger, // Optional: defaults to console when logLevel is set
})Log Levels
| Level | Value | Description |
|-------|-------|-------------|
| LogLevel.NONE | 0 | No logging (default) |
| LogLevel.ERROR | 1 | Error messages only |
| LogLevel.WARN | 2 | Warnings and errors |
| LogLevel.INFO | 3 | Info, warnings, and errors |
| LogLevel.DEBUG | 4 | All messages including debug info |
Built-in Loggers
| Logger | Description |
|--------|-------------|
| consoleLogger | Logs to browser console (used automatically when logLevel is set) |
| silentLogger | No output - useful for explicitly disabling logs |
Behavior
- Silent by default: No logging occurs unless explicitly configured
- Smart defaults: When you set a
logLevel,consoleLoggeris used automatically - Custom loggers: Provide your own
loggerfor custom logging behavior - OIDC integration: Both internal auth logs and underlying OIDC client logs are controlled by the same configuration
Custom Logger
Implement the Logger interface for custom logging:
import type { Logger } from 'vuethenticate'
const customLogger: Logger = {
error: (message, ...args) => {
// Send to error reporting service
errorService.log(message, args)
},
warn: (message, ...args) => console.warn(message, ...args),
info: (message, ...args) => console.info(message, ...args),
debug: (message, ...args) => {
if (process.env.NODE_ENV === 'development') {
console.debug(message, ...args)
}
},
}
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
logLevel: LogLevel.INFO,
logger: customLogger,
})What Gets Logged
With logging enabled, you'll see detailed information about:
- Authentication flows: Sign-in, sign-out, and callback processing
- Token management: Token refresh, expiration, and renewal
- OIDC protocol: Requests, responses, and protocol-level details
- Error handling: Detailed error information with stack traces
- State management: User loading/unloading events
Development vs Production
const auth = useAuth({
authority: 'https://your-oidc-provider.com',
clientId: 'your-client-id',
// Enable detailed logging only in development
logLevel: process.env.NODE_ENV === 'development'
? LogLevel.DEBUG
: LogLevel.ERROR,
})Advanced Usage
Manual Authentication State Reset
The resetAuthState() method provides a way to manually clear authentication state and remove the user from storage. This is useful for custom logout flows or error recovery scenarios.
const auth = useAuth(config);
// Manually reset authentication state
await auth.resetAuthState();
// This will:
// - Remove user from storage
// - Clear reactive user state
// - Log the operation
// - Handle any errors that occur during removalCommon use cases:
- Custom logout flows that don't use the standard OAuth logout endpoint
- Error recovery when authentication state becomes corrupted
- Implementing "sign out from all devices" functionality
- Testing scenarios where you need to reset authentication state
Error Handling and State Recovery
All callback components (AuthCallback, LogoutCallback, SilentCallback) now automatically handle errors by resetting authentication state. When an error occurs during callback processing:
- The error is logged with appropriate details
- Authentication state is automatically reset via
resetAuthState() - The error is re-thrown for your application to handle
This ensures that failed authentication flows don't leave the application in an inconsistent state.
// Callback components automatically handle errors and reset state
// No additional error handling required for state consistencyManual Cleanup
The useAuth composable includes a cleanup() function for manual resource cleanup. This is rarely needed as the library manages resources automatically.
const auth = useAuth(config);
// Only use in special scenarios like testing or custom cleanup requirements
auth.cleanup();When you might need cleanup:
- Unit testing scenarios where you need to reset state between tests
- Dynamic configuration changes (though creating a new instance is usually better)
- Custom cleanup logic in very specific edge cases
Note: The cleanup function removes event listeners and clears the UserManager instance from the internal registry. Normal application usage should never require calling this function.
License
MIT
