diff --git a/components/layout/full/vertical-header/ProfileDD.vue b/components/layout/full/vertical-header/ProfileDD.vue index d34c62e..ca2a13c 100644 --- a/components/layout/full/vertical-header/ProfileDD.vue +++ b/components/layout/full/vertical-header/ProfileDD.vue @@ -64,7 +64,7 @@ const sessionInfo = computed(() => ({ - +
User Profile
diff --git a/composables/useAuth.ts b/composables/useAuth.ts index 59102b2..b6abd4b 100644 --- a/composables/useAuth.ts +++ b/composables/useAuth.ts @@ -107,6 +107,9 @@ export const useAuth = () => { const response = await $fetch('/api/auth/logout', { method: 'POST' }) + // const response = await $fetch('/api/auth/clear-session', { + // method: 'POST' + // }); // Clear user immediately regardless of response _user.value = null diff --git a/pages/antrean/all.vue b/pages/antrean/all.vue index ad03fd0..f013664 100644 --- a/pages/antrean/all.vue +++ b/pages/antrean/all.vue @@ -64,8 +64,8 @@ const filterOptions = [ modelKey: 'sortOption', options: [ { label: 'Default', value: null }, - { label: 'Tanggal Daftar ⬆', value: 'tanggal_daftar|DESC' }, - { label: 'Tanggal Daftar ⬇', value: 'tanggal_daftar|ASC' } + { label: 'Tanggal Daftar (Terbaru)', value: 'tanggal_daftar|DESC' }, + { label: 'Tanggal Daftar (Terlama)', value: 'tanggal_daftar|ASC' } ], defaultValue: null } diff --git a/pages/antrean/kategori/[id].vue b/pages/antrean/kategori/[id].vue index d2d36cf..1caafd1 100644 --- a/pages/antrean/kategori/[id].vue +++ b/pages/antrean/kategori/[id].vue @@ -61,8 +61,8 @@ const filterOptions = [ modelKey: 'sortOption', options: [ { label: 'Default', value: null }, - { label: 'Tanggal Daftar ⬆', value: 'tanggal_daftar|DESC' }, - { label: 'Tanggal Daftar ⬇', value: 'tanggal_daftar|ASC' } + { label: 'Tanggal Daftar (Terbaru)', value: 'tanggal_daftar|DESC' }, + { label: 'Tanggal Daftar (Terlama)', value: 'tanggal_daftar|ASC' } ], defaultValue: null } diff --git a/pages/antrean/spesialis/[kode].vue b/pages/antrean/spesialis/[kode].vue index 1273edf..8519ec0 100644 --- a/pages/antrean/spesialis/[kode].vue +++ b/pages/antrean/spesialis/[kode].vue @@ -61,8 +61,8 @@ const filterOptions = [ modelKey: 'sortOption', options: [ { label: 'Default', value: null }, - { label: 'Tanggal Daftar ⬆', value: 'tanggal_daftar|DESC' }, - { label: 'Tanggal Daftar ⬇', value: 'tanggal_daftar|ASC' } + { label: 'Tanggal Daftar (Terbaru)', value: 'tanggal_daftar|DESC' }, + { label: 'Tanggal Daftar (Terlama)', value: 'tanggal_daftar|ASC' } ], defaultValue: null } diff --git a/pages/antrean/subspesialis/[kode].vue b/pages/antrean/subspesialis/[kode].vue index 8cbfa05..d3b0800 100644 --- a/pages/antrean/subspesialis/[kode].vue +++ b/pages/antrean/subspesialis/[kode].vue @@ -61,8 +61,8 @@ const filterOptions = [ modelKey: 'sortOption', options: [ { label: 'Default', value: null }, - { label: 'Tanggal Daftar ⬆', value: 'tanggal_daftar|DESC' }, - { label: 'Tanggal Daftar ⬇', value: 'tanggal_daftar|ASC' } + { label: 'Tanggal Daftar (Terbaru)', value: 'tanggal_daftar|DESC' }, + { label: 'Tanggal Daftar (Terlama)', value: 'tanggal_daftar|ASC' } ], defaultValue: null } diff --git a/server/api/auth/clear-session.post.ts b/server/api/auth/clear-session.post.ts new file mode 100644 index 0000000..5ce80e1 --- /dev/null +++ b/server/api/auth/clear-session.post.ts @@ -0,0 +1,77 @@ +// server/api/auth/clear-session.post.ts +// Endpoint to forcefully clear session cookies and logout from Keycloak +export default defineEventHandler(async (event) => { + try { + const config = useRuntimeConfig(); + console.log('🧹 Clear session endpoint called'); + + // Get the current session to retrieve ID token for Keycloak logout + const sessionCookie = getCookie(event, 'user_session'); + let idToken = null; + + if (sessionCookie) { + try { + // Try to decode JWT-based session from cookie + const sessionJson = Buffer.from(sessionCookie, 'base64').toString('utf-8'); + const session = JSON.parse(sessionJson); + idToken = session.idToken; + console.log('🔑 ID token found for Keycloak logout'); + } catch (error) { + console.warn('⚠️ Could not parse session cookie (might be old format)'); + // Continue anyway to clear cookies + } + } + + // Clear all auth-related cookies + console.log('🧹 Clearing all session cookies...'); + deleteCookie(event, 'user_session'); + deleteCookie(event, 'oauth_state'); + + // Also clear with different path variations + deleteCookie(event, 'user_session', { path: '/' }); + deleteCookie(event, 'oauth_state', { path: '/' }); + + console.log('✅ Local session cleared successfully'); + + // Build Keycloak logout URL + const logoutPath = config.keycloakLogoutUri || `${config.keycloakIssuer}/protocol/openid-connect/logout`; + const logoutUrl = new URL(logoutPath); + + const postLogoutRedirectUri = config.postLogoutRedirectUri || `${config.public.authUrl}/LoginPage?logout=success`; + + logoutUrl.searchParams.set('client_id', config.keycloakClientId); + logoutUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri); + + // Add ID token hint if available for proper Keycloak session termination + if (idToken) { + logoutUrl.searchParams.set('id_token_hint', idToken); + console.log('🔑 Added id_token_hint to Keycloak logout URL'); + } + + console.log('🔗 Keycloak logout URL:', logoutUrl.toString()); + + return { + success: true, + logoutUrl: logoutUrl.toString(), + message: 'Session cleared successfully. Redirecting to Keycloak logout...' + }; + + } catch (error: any) { + console.error('❌ Clear session error:', error); + + // Even on error, provide a basic logout URL + const config = useRuntimeConfig(); + const postLogoutRedirectUri = config.postLogoutRedirectUri || `${config.public.authUrl}/LoginPage?logout=success`; + const logoutPath = config.keycloakLogoutUri || `${config.keycloakIssuer}/protocol/openid-connect/logout`; + const fallbackLogoutUrl = new URL(logoutPath); + fallbackLogoutUrl.searchParams.set('client_id', config.keycloakClientId); + fallbackLogoutUrl.searchParams.set('post_logout_redirect_uri', postLogoutRedirectUri); + + return { + success: false, + logoutUrl: fallbackLogoutUrl.toString(), + error: 'Error during session cleanup', + message: error.message + }; + } +});