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

126 lines
4.9 KiB
TypeScript

// server/api/users/current.get.ts
// Get current logged-in user data from JWT token
// Helper function to decode JWT token payload
const decodeTokenPayload = (token: string | undefined): any | null => {
if (!token) return null;
try {
const parts = token.split(".");
if (parts.length < 2) return null;
const payloadBase64 = parts[1];
return JSON.parse(Buffer.from(payloadBase64, "base64").toString());
} catch (e) {
console.error("❌ Failed to decode token payload:", e);
return null;
}
};
export default defineEventHandler(async (event) => {
console.log("🔍 Current user endpoint called");
// Get session from session store using session ID from cookie
const { getSessionFromCookie } = await import('~/server/utils/sessionStore');
const session = await getSessionFromCookie(event);
if (!session) {
throw createError({
statusCode: 401,
statusMessage: "No session found or session expired",
});
}
try {
// Decode tokens to get full user data
const idTokenPayload = decodeTokenPayload(session.idToken);
const accessTokenPayload = decodeTokenPayload(session.accessToken);
// Extract roles from different sources
const realmRoles = accessTokenPayload?.realm_access?.roles ||
idTokenPayload?.realm_access?.roles ||
[];
const accountRoles = accessTokenPayload?.resource_access?.account?.roles ||
idTokenPayload?.resource_access?.account?.roles ||
[];
// Extract resource roles (from all resources in resource_access)
const resourceRoles: string[] = [];
if (accessTokenPayload?.resource_access) {
Object.keys(accessTokenPayload.resource_access).forEach(resourceName => {
if (resourceName !== 'account') { // Exclude account, already handled
const resourceRolesArray = accessTokenPayload.resource_access[resourceName]?.roles || [];
resourceRoles.push(...resourceRolesArray.map((role: string) => `${resourceName}:${role}`));
}
});
}
if (idTokenPayload?.resource_access) {
Object.keys(idTokenPayload.resource_access).forEach(resourceName => {
if (resourceName !== 'account') { // Exclude account, already handled
const resourceRolesArray = idTokenPayload.resource_access[resourceName]?.roles || [];
resourceRoles.push(...resourceRolesArray.map((role: string) => `${resourceName}:${role}`));
}
});
}
// Legacy: Combined roles (for backward compatibility)
const roles = [...realmRoles, ...accountRoles, ...resourceRoles];
// Keycloak uses 'groups_join' in access token, not 'groups'
const groups = accessTokenPayload?.groups_join ||
accessTokenPayload?.groups ||
idTokenPayload?.groups_join ||
idTokenPayload?.groups ||
[];
// Determine tipeUser from groups or roles if possible
// You can customize this mapping based on your business logic
let tipeUser = '';
if (Array.isArray(groups) && groups.length > 0) {
// Extract tipeUser from groups path (e.g., "/Instalasi STIM/Devops/Superadmin" -> "Superadmin")
const lastGroup = groups[groups.length - 1];
if (typeof lastGroup === 'string') {
const parts = lastGroup.split('/').filter(Boolean);
if (parts.length > 0) {
tipeUser = parts[parts.length - 1]; // Get last part of path
}
}
}
// Build user data object
const userData = {
id: idTokenPayload?.sub || session.user?.id,
namaLengkap: idTokenPayload?.name ||
session.user?.name ||
`${idTokenPayload?.given_name || ''} ${idTokenPayload?.family_name || ''}`.trim() ||
idTokenPayload?.preferred_username,
namaUser: idTokenPayload?.preferred_username ||
session.user?.preferred_username ||
idTokenPayload?.email?.split('@')[0],
email: idTokenPayload?.email || session.user?.email,
given_name: idTokenPayload?.given_name,
family_name: idTokenPayload?.family_name,
roles: Array.isArray(roles) ? roles : [],
realmRoles: Array.isArray(realmRoles) ? realmRoles : [],
accountRoles: Array.isArray(accountRoles) ? accountRoles : [],
resourceRoles: Array.isArray(resourceRoles) ? resourceRoles : [],
groups: Array.isArray(groups) ? groups : [],
tipeUser: tipeUser, // Extracted from groups or empty
lastLogin: null, // Will be set on sync
// Include full token payloads for reference
idTokenPayload,
accessTokenPayload,
};
console.log("✅ Current user data extracted from JWT");
return userData;
} catch (parseError: any) {
console.error("❌ Failed to parse session or extract user data:", parseError);
throw createError({
statusCode: 401,
statusMessage: "Invalid session data",
});
}
});