Session Composables
Vue 3 composables for managing JWT-based sessions with automatic encryption, token refresh, and session lifecycle management.
useSessionStart
Create a new session with encrypted JWT token.
Basic Session Start
<script setup lang="ts">
import { useSessionStart } from '@ductape/vue';
const { mutate: startSession, isLoading, data, error } = useSessionStart({
onSuccess: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
console.log('Session started:', result.sessionId);
},
onError: (error) => {
alert('Failed to start session: ' + error.message);
}
});
const handleLogin = async (userId: string, email: string) => {
// After validating credentials, start the session
startSession({
tag: 'user-session',
data: {
userId,
email,
role: 'user'
},
identifier: userId
});
};
</script>
<template>
<div>
<button
@click="handleLogin('user-123', 'user@example.com')"
:disabled="isLoading"
>
{{ isLoading ? 'Starting Session...' : 'Log In' }}
</button>
<div v-if="data">
<p>Session ID: {{ data.sessionId }}</p>
<p>Expires: {{ new Date(data.expiresAt).toLocaleString() }}</p>
</div>
<p v-if="error" style="color: red">{{ error.message }}</p>
</div>
</template>
With Custom Expiration
<script setup lang="ts">
import { useSessionStart } from '@ductape/vue';
const { mutate: startSession, isLoading } = useSessionStart({
onSuccess: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
}
});
const handleStartExtendedSession = () => {
startSession({
tag: 'user-session',
data: {
userId: 'user-123',
email: 'user@example.com',
role: 'admin'
},
identifier: 'user-123',
expiresIn: 7 * 24 * 60 * 60 // 7 days in seconds
});
};
</script>
<template>
<button @click="handleStartExtendedSession" :disabled="isLoading">
Start 7-Day Session
</button>
</template>
Admin Session Example
<script setup lang="ts">
import { useSessionStart } from '@ductape/vue';
const { mutate: startSession, data } = useSessionStart({
onSuccess: (result) => {
localStorage.setItem('adminToken', result.token);
localStorage.setItem('adminRefreshToken', result.refreshToken);
}
});
const handleAdminLogin = () => {
startSession({
tag: 'admin-session',
data: {
userId: 'admin-456',
email: 'admin@company.com',
role: 'admin',
permissions: ['users.manage', 'content.edit', 'reports.view']
},
identifier: 'admin-456'
});
};
</script>
<template>
<button @click="handleAdminLogin">
Start Admin Session
</button>
</template>
useSessionVerify
Verify and decode a JWT session token.
Basic Token Verification
<script setup lang="ts">
import { useSessionVerify } from '@ductape/vue';
import { onMounted } from 'vue';
const { mutate: verifySession, data, isLoading, error } = useSessionVerify({
onSuccess: (result) => {
console.log('Session valid:', result.data);
console.log('Expires at:', new Date(result.expiresAt));
},
onError: (error) => {
// Token invalid or expired
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
}
});
onMounted(() => {
const token = localStorage.getItem('token');
if (token) {
verifySession({
tag: 'user-session',
token
});
}
});
</script>
<template>
<div v-if="isLoading">Verifying session...</div>
<div v-else-if="error">
Session expired. Please log in again.
</div>
<div v-else-if="data">
<h2>Welcome back!</h2>
<p>User ID: {{ data.data.userId }}</p>
<p>Email: {{ data.data.email }}</p>
<p>Role: {{ data.data.role }}</p>
<p>Session expires: {{ new Date(data.expiresAt).toLocaleString() }}</p>
</div>
</template>
Protected Route Component
<script setup lang="ts">
import { useSessionVerify } from '@ductape/vue';
import { useRouter } from 'vue-router';
import { onMounted, watch } from 'vue';
const router = useRouter();
const { mutate: verifySession, data, isLoading } = useSessionVerify();
onMounted(() => {
const token = localStorage.getItem('token');
if (token) {
verifySession({
tag: 'user-session',
token
});
}
});
watch([isLoading, data], ([loading, sessionData]) => {
if (!loading && !sessionData) {
router.push('/login');
}
});
</script>
<template>
<div v-if="isLoading">
Verifying access...
</div>
<div v-else-if="data">
<slot />
</div>
</template>
Role-Based Access Control
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useSessionVerify } from '@ductape/vue';
const hasAccess = ref(false);
const { mutate: verifySession, isLoading } = useSessionVerify({
onSuccess: (result) => {
if (result.data.role === 'admin') {
hasAccess.value = true;
} else {
alert('Admin access required');
}
}
});
onMounted(() => {
const token = localStorage.getItem('token');
if (token) {
verifySession({
tag: 'admin-session',
token
});
}
});
</script>
<template>
<div v-if="isLoading">Checking permissions...</div>
<div v-else-if="!hasAccess">
Access denied. Admin role required.
</div>
<div v-else>
<h1>Admin Dashboard</h1>
<!-- Admin content -->
</div>
</template>
useSessionRefresh
Refresh an expiring session token using a refresh token.
Manual Token Refresh
<script setup lang="ts">
import { useSessionRefresh } from '@ductape/vue';
const { mutate: refreshSession, isLoading } = useSessionRefresh({
onSuccess: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
alert('Session refreshed successfully');
},
onError: (error) => {
alert('Failed to refresh session. Please log in again.');
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
}
});
const handleRefresh = () => {
const refreshToken = localStorage.getItem('refreshToken');
if (refreshToken) {
refreshSession({
tag: 'user-session',
refreshToken
});
}
};
</script>
<template>
<button @click="handleRefresh" :disabled="isLoading">
{{ isLoading ? 'Refreshing...' : 'Refresh Session' }}
</button>
</template>
Conditional Refresh Based on Expiry
<script setup lang="ts">
import { watch } from 'vue';
import { useSessionVerify, useSessionRefresh } from '@ductape/vue';
const { mutate: verifySession, data } = useSessionVerify();
const { mutate: refreshSession } = useSessionRefresh({
onSuccess: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
}
});
onMounted(() => {
const token = localStorage.getItem('token');
if (token) {
verifySession({
tag: 'user-session',
token
});
}
});
watch(data, (sessionData) => {
if (!sessionData) return;
const expiresAt = new Date(sessionData.expiresAt).getTime();
const now = Date.now();
const fiveMinutes = 5 * 60 * 1000;
// Refresh if expires in less than 5 minutes
if (expiresAt - now < fiveMinutes) {
const refreshToken = localStorage.getItem('refreshToken');
if (refreshToken) {
refreshSession({
tag: 'user-session',
refreshToken
});
}
}
});
</script>
<template>
<!-- Background component -->
</template>
useSessionAutoRefresh
Automatically refresh tokens before they expire.
Basic Auto-Refresh Setup
<script setup lang="ts">
import { useSessionAutoRefresh } from '@ductape/vue';
import { onMounted } from 'vue';
const { isActive, currentToken, start, stop } = useSessionAutoRefresh({
tag: 'user-session',
refreshToken: localStorage.getItem('refreshToken') || '',
refreshBefore: 5 * 60, // Refresh 5 minutes before expiry
onRefresh: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
console.log('Session auto-refreshed');
},
onError: (error) => {
console.error('Auto-refresh failed:', error);
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
// Redirect to login
}
});
onMounted(() => {
const token = localStorage.getItem('token');
const refreshToken = localStorage.getItem('refreshToken');
if (token && refreshToken) {
start();
}
});
</script>
<template>
<slot />
</template>
Complete Auth Provider
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import {
useSessionStart,
useSessionVerify,
useSessionAutoRefresh
} from '@ductape/vue';
const user = ref<any | null>(null);
const { start: startAutoRefresh, stop: stopAutoRefresh } = useSessionAutoRefresh({
tag: 'user-session',
refreshToken: localStorage.getItem('refreshToken') || '',
onRefresh: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
}
});
const { mutate: startSession } = useSessionStart();
const { mutate: verifySession } = useSessionVerify();
onMounted(() => {
// Verify existing session on mount
const token = localStorage.getItem('token');
const refreshToken = localStorage.getItem('refreshToken');
if (token && refreshToken) {
verifySession(
{
tag: 'user-session',
token
},
{
onSuccess: (result) => {
user.value = result.data;
startAutoRefresh();
},
onError: () => {
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
}
}
);
}
});
const login = (userId: string, email: string) => {
startSession(
{
tag: 'user-session',
data: { userId, email, role: 'user' },
identifier: userId
},
{
onSuccess: (result) => {
localStorage.setItem('token', result.token);
localStorage.setItem('refreshToken', result.refreshToken);
user.value = { userId, email, role: 'user' };
startAutoRefresh();
}
}
);
};
const logout = () => {
stopAutoRefresh();
localStorage.removeItem('token');
localStorage.removeItem('refreshToken');
user.value = null;
};
// Provide these methods to child components via provide/inject if needed
defineExpose({ user, login, logout });
</script>
<template>
<slot :user="user" :login="login" :logout="logout" />
</template>