126 lines
4.9 KiB
TypeScript
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",
|
|
});
|
|
}
|
|
});
|
|
|