fix(FE) : fix store token

This commit is contained in:
Yusron alamsyah
2026-02-24 14:33:16 +07:00
parent b122aa6dad
commit 23f668ae3f
7 changed files with 134 additions and 101 deletions
+11 -13
View File
@@ -129,6 +129,7 @@ export default defineEventHandler(async (event) => {
let idTokenPayload;
let accessTokenPayload;
let refreshTokenPayload;
try {
idTokenPayload = JSON.parse(
Buffer.from(tokens.id_token.split('.')[1], 'base64').toString()
@@ -136,23 +137,22 @@ export default defineEventHandler(async (event) => {
accessTokenPayload = JSON.parse(
Buffer.from(tokens.access_token.split('.')[1], 'base64').toString()
);
refreshTokenPayload = JSON.parse(
Buffer.from(tokens.refresh_token.split('.')[1], 'base64').toString()
);
} catch (decodeError) {
console.error('❌ Failed to decode ID token:', decodeError);
const errorMsg = encodeURIComponent('Invalid ID token format');
console.error('❌ Failed to decode token:', decodeError);
const errorMsg = encodeURIComponent('Invalid token format');
return sendRedirect(event, `/auth/login?error=${errorMsg}`);
}
// Extract roles from Keycloak token
// Keycloak stores roles in different places depending on configuration
const realmRoles = accessTokenPayload.realm_access?.roles || [];
const clientRoles = accessTokenPayload.resource_access?.[config.keycloakClientId]?.roles || [];
const allRoles = [...new Set([...realmRoles, ...clientRoles])]; // Remove duplicates
console.log('👥 User Roles Extracted:');
console.log(' - Realm Roles:', realmRoles);
console.log(' - Client Roles:', clientRoles);
console.log(' - All Roles:', allRoles);
console.log("refreshTokenPayload.exp:", refreshTokenPayload.exp);
console.log("Current time (seconds):", Math.floor(Date.now() / 1000));
console.log("Token expires in (seconds):", refreshTokenPayload.exp - Math.floor(Date.now() / 1000));
// Store minimal session data in cookie to reduce size
// The ID token contains user info, so we can decode it when needed
const sessionData = {
@@ -162,8 +162,6 @@ export default defineEventHandler(async (event) => {
email: idTokenPayload.email,
name: idTokenPayload.name || idTokenPayload.preferred_username,
preferred_username: idTokenPayload.preferred_username,
roles: allRoles, // All user roles combined
realm_roles: realmRoles, // Realm-specific roles
client_roles: clientRoles, // Client-specific roles
},
// Store tokens - these are necessary for API calls
@@ -172,8 +170,8 @@ export default defineEventHandler(async (event) => {
idToken: tokens.id_token,
refreshToken: tokens.refresh_token,
// Session metadata
expiresAt: Date.now() + (SESSION_DURATION * 1000),
createdAt: Date.now(),
expiresAt: refreshTokenPayload.exp * 1000, // Convert to milliseconds
createdAt: refreshTokenPayload.iat ? refreshTokenPayload.iat * 1000 : Date.now(),
};
// Determine if we should use secure cookies
+3 -3
View File
@@ -67,6 +67,7 @@ export default defineEventHandler(async (event) => {
// Decode tokens and prepare the enhanced response data
const idTokenPayload = decodeTokenPayload(session.idToken);
const accessTokenPayload = decodeTokenPayload(session.accessToken);
const refreshTokenPayload = decodeTokenPayload(session.refreshToken);
// Final response object - ensure it matches SessionResponse interface
const sessionResponse: SessionResponse & {
@@ -85,13 +86,12 @@ export default defineEventHandler(async (event) => {
refreshToken: session.refreshToken,
// Session Timestamps (optional in SessionResponse)
expiresAt: session.expiresAt,
expiresAt: refreshTokenPayload?.exp ? refreshTokenPayload.exp * 1000 : session.expiresAt,
// Additional debug fields (not in SessionResponse interface)
idToken: session.idToken,
idTokenPayload: idTokenPayload,
accessTokenPayload: accessTokenPayload,
fullSessionObject: session,
// fullSessionObject: session,
status: "authenticated",
};
+71
View File
@@ -0,0 +1,71 @@
// server/api/auth/session.patch.ts
export default defineEventHandler(async (event) => {
console.log("🔄 Session update endpoint called");
const sessionId = getCookie(event, "user_session");
if (!sessionId) {
console.log("❌ No session cookie found");
throw createError({
statusCode: 401,
statusMessage: "No session cookie found",
});
}
try {
// Get the update data from request body
const body = await readBody(event);
const { accessToken, idToken, refreshToken, expiresAt } = body;
// Validate that at least one token is provided
if (!accessToken && !idToken && !refreshToken) {
throw createError({
statusCode: 400,
statusMessage: "At least one token must be provided",
});
}
// Get session store functions
const { getSession, updateSession } = await import('~/server/utils/sessionStore');
// Verify session exists
const session = getSession(sessionId);
if (!session) {
console.log("❌ Session not found");
deleteCookie(event, "user_session");
throw createError({
statusCode: 401,
statusMessage: "Session not found or expired",
});
}
// Prepare updates object
const updates: any = {};
if (accessToken) updates.accessToken = accessToken;
if (idToken) updates.idToken = idToken;
if (refreshToken) updates.refreshToken = refreshToken;
if (expiresAt) updates.expiresAt = expiresAt;
// Update the session
const updated = updateSession(sessionId, updates);
if (!updated) {
throw createError({
statusCode: 500,
statusMessage: "Failed to update session",
});
}
console.log("✅ Session updated successfully");
return {
success: true,
message: "Session updated successfully",
};
} catch (error: any) {
console.error("❌ Failed to update session:", error);
throw createError({
statusCode: error.statusCode || 500,
statusMessage: error.statusMessage || "Failed to update session",
});
}
});