Files
web-antrean/server/api/users/last-access.get.ts
T
2026-01-07 07:50:25 +07:00

87 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// server/api/users/last-access.get.ts
// Get last access time from Keycloak Admin API for a specific user using access token from session
export default defineEventHandler(async (event) => {
console.log("🔍 Last access endpoint called");
const query = getQuery(event);
const userId = query.userId as string;
if (!userId) {
throw createError({
statusCode: 400,
statusMessage: "userId is required",
});
}
try {
const config = useRuntimeConfig();
// Get access token from current user session
let accessToken: string | null = null;
try {
const { getSessionFromCookie } = await import('~/server/utils/sessionStore');
const session = await getSessionFromCookie(event);
if (session && session.accessToken) {
accessToken = session.accessToken;
}
} catch (e) {
console.warn("⚠️ No valid session found");
}
if (!accessToken) {
return { lastAccess: null };
}
// Extract realm from issuer (e.g., "http://keycloak:8080/realms/sandbox" -> "sandbox")
const issuerUrl = new URL(config.keycloakIssuer);
const realm = issuerUrl.pathname.split('/').filter(Boolean).pop() || 'master';
// Get user sessions from Keycloak Admin API using access token
const sessionsUrl = `${config.keycloakIssuer.replace('/realms/' + realm, '')}/admin/realms/${realm}/users/${userId}/sessions`;
const sessionsResponse = await fetch(sessionsUrl, {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});
if (!sessionsResponse.ok) {
// If user has no sessions or no permission, return null
if (sessionsResponse.status === 404 || sessionsResponse.status === 403) {
console.log(`️ No sessions found or no permission for user ${userId}`);
return { lastAccess: null };
}
return { lastAccess: null };
}
const sessions = await sessionsResponse.json() as any[];
if (!sessions || sessions.length === 0) {
console.log(`️ No active sessions for user ${userId}`);
return { lastAccess: null };
}
// Find the most recent session (highest lastAccess timestamp)
let lastAccessTimestamp = 0;
sessions.forEach(session => {
if (session.lastAccess && session.lastAccess > lastAccessTimestamp) {
lastAccessTimestamp = session.lastAccess;
}
});
// Convert from milliseconds to seconds (Unix timestamp)
const lastAccess = lastAccessTimestamp > 0 ? Math.floor(lastAccessTimestamp / 1000) : null;
console.log(`✅ Last access for user ${userId}: ${lastAccess ? new Date(lastAccess * 1000).toISOString() : 'Never'}`);
return { lastAccess };
} catch (error: any) {
console.error("❌ Error fetching last access from Keycloak:", error);
// Return null instead of throwing error to allow graceful degradation
return { lastAccess: null };
}
});